From a922e325f0fdd19ac1069c5dd4745a0762fd8fce Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Thu, 9 Apr 2026 14:50:01 +0300 Subject: [PATCH 01/36] ring-proof switched to SW jubjub --- w3f-ring-proof/benches/ring_proof.rs | 30 +++++++++---------- w3f-ring-proof/src/lib.rs | 24 +++++++-------- .../src/multi_ring_batch_verifier.rs | 10 +++---- w3f-ring-proof/src/piop/mod.rs | 8 ++--- w3f-ring-proof/src/piop/params.rs | 16 +++++----- w3f-ring-proof/src/piop/prover.rs | 8 ++--- w3f-ring-proof/src/piop/verifier.rs | 4 +-- w3f-ring-proof/src/ring.rs | 26 ++++++++-------- w3f-ring-proof/src/ring_prover.rs | 6 ++-- w3f-ring-proof/src/ring_verifier.rs | 14 ++++----- 10 files changed, 73 insertions(+), 73 deletions(-) diff --git a/w3f-ring-proof/benches/ring_proof.rs b/w3f-ring-proof/benches/ring_proof.rs index b0ab568..f9816d8 100644 --- a/w3f-ring-proof/benches/ring_proof.rs +++ b/w3f-ring-proof/benches/ring_proof.rs @@ -2,7 +2,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criteri use ark_bls12_381::Bls12_381; use ark_ec::CurveGroup; -use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, EdwardsAffine, Fq, Fr}; +use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine, Fq, Fr}; use ark_serialize::CanonicalSerialize; use ark_std::ops::Mul; use ark_std::rand::Rng; @@ -25,9 +25,9 @@ fn setup( let setup_degree = 3 * domain_size; let pcs_params = CS::setup(setup_degree, rng); let domain = Domain::new(domain_size, true); - let h = EdwardsAffine::rand(rng); - let seed = EdwardsAffine::rand(rng); - let padding = EdwardsAffine::rand(rng); + let h = SWAffine::rand(rng); + let seed = SWAffine::rand(rng); + let padding = SWAffine::rand(rng); let piop_params = PiopParams::setup(domain, h, seed, padding); (pcs_params, piop_params) } @@ -37,7 +37,7 @@ fn make_transcript() -> ArkTranscript { } /// Get the Pedersen blinding base H from the PIOP params (first element of the power-of-2 multiples). -fn get_h(piop_params: &PiopParams) -> EdwardsAffine { +fn get_h(piop_params: &PiopParams) -> SWAffine { piop_params.power_of_2_multiples_of_h()[0] } @@ -45,9 +45,9 @@ fn get_h(piop_params: &PiopParams) -> EdwardsAffine { fn generate_proof( piop_params: &PiopParams, pcs_params: &>::Params, - pks: &[EdwardsAffine], + pks: &[SWAffine], rng: &mut impl Rng, -) -> (EdwardsAffine, RingProof) { +) -> (SWAffine, RingProof) { let h = get_h(piop_params); let prover_idx = rng.gen_range(0..pks.len()); let (prover_key, _) = index::<_, CS, _>(pcs_params, piop_params, pks); @@ -86,7 +86,7 @@ fn bench_index(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); group.bench_with_input(BenchmarkId::new("full_keyset", n), &n, |b, _| { b.iter(|| index::<_, CS, _>(&pcs_params, &piop_params, &pks)); @@ -104,7 +104,7 @@ fn bench_prove(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (prover_key, _) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); let prover_idx = rng.gen_range(0..keyset_size); @@ -132,7 +132,7 @@ fn bench_verify(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (blinded_pk, proof) = generate_proof(&piop_params, &pcs_params, &pks, rng); let (_, verifier_key) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); @@ -154,11 +154,11 @@ fn bench_verify_batch_sequential(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); // Pre-generate proofs for the largest batch. let max_batch = 32; - let claims: Vec<(EdwardsAffine, RingProof)> = (0..max_batch) + let claims: Vec<(SWAffine, RingProof)> = (0..max_batch) .map(|_| generate_proof(&piop_params, &pcs_params, &pks, rng)) .collect(); @@ -188,10 +188,10 @@ fn bench_verify_batch_kzg(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let max_batch = 32; - let claims: Vec<(EdwardsAffine, RingProof)> = (0..max_batch) + let claims: Vec<(SWAffine, RingProof)> = (0..max_batch) .map(|_| generate_proof(&piop_params, &pcs_params, &pks, rng)) .collect(); @@ -227,7 +227,7 @@ fn bench_proof_size(c: &mut Criterion) { let n = 1usize << 10; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (_, proof) = generate_proof(&piop_params, &pcs_params, &pks, rng); diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index d2e355e..c600c0f 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -53,7 +53,7 @@ impl ArkTranscript { mod tests { use ark_bls12_381::Bls12_381; use ark_ec::CurveGroup; - use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, EdwardsAffine, Fq, Fr}; + use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine, Fq, Fr}; use ark_std::ops::Mul; use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, test_rng, UniformRand}; @@ -73,17 +73,17 @@ mod tests { batch_size: usize, ) -> ( RingVerifier, - Vec<(EdwardsAffine, RingProof)>, + Vec<(SWAffine, RingProof)>, ) { let rng = &mut test_rng(); let (pcs_params, piop_params) = setup::<_, CS>(rng, domain_size); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (prover_key, verifier_key) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); let t_prove = start_timer!(|| "Prove"); - let claims: Vec<(EdwardsAffine, RingProof)> = (0..batch_size) + let claims: Vec<(SWAffine, RingProof)> = (0..batch_size) .map(|_| { let prover_idx = rng.gen_range(0..keyset_size); let prover = RingProver::init( @@ -125,7 +125,7 @@ mod tests { let max_keyset_size = piop_params.keyset_part_size; let keyset_size: usize = rng.gen_range(0..max_keyset_size); - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (_, verifier_key) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks); @@ -146,9 +146,9 @@ mod tests { let pcs_params = CS::setup(setup_degree, rng); let domain = Domain::new(domain_size, true); - let h = EdwardsAffine::rand(rng); - let seed = EdwardsAffine::rand(rng); - let padding = EdwardsAffine::rand(rng); + let h = SWAffine::rand(rng); + let seed = SWAffine::rand(rng); + let padding = SWAffine::rand(rng); let piop_params = PiopParams::setup(domain, h, seed, padding); (pcs_params, piop_params) @@ -197,18 +197,18 @@ mod tests { // Ring A let keyset_size_a = piop_params.keyset_part_size; - let pks_a = random_vec::(keyset_size_a, rng); + let pks_a = random_vec::(keyset_size_a, rng); let (prover_key_a, verifier_key_a) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks_a); // Ring B (smaller keyset) let keyset_size_b = piop_params.keyset_part_size / 2; - let pks_b = random_vec::(keyset_size_b, rng); + let pks_b = random_vec::(keyset_size_b, rng); let (prover_key_b, verifier_key_b) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks_b); - let mut generate_claims = |prover_key: &ProverKey, EdwardsAffine>, - pks: &[EdwardsAffine], + let mut generate_claims = |prover_key: &ProverKey, SWAffine>, + pks: &[SWAffine], keyset_size: usize| { (0..proofs_per_ring) .map(|_| { diff --git a/w3f-ring-proof/src/multi_ring_batch_verifier.rs b/w3f-ring-proof/src/multi_ring_batch_verifier.rs index 3d048f5..69b0eba 100644 --- a/w3f-ring-proof/src/multi_ring_batch_verifier.rs +++ b/w3f-ring-proof/src/multi_ring_batch_verifier.rs @@ -1,5 +1,5 @@ use ark_ec::pairing::Pairing; -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; use ark_std::rand::RngCore; use w3f_pcs::pcs::kzg::params::KzgVerifierKey; @@ -21,7 +21,7 @@ use crate::RingProof; pub struct PreparedMultiRingItem<'a, E, J, T> where E: Pairing, - J: TECurveConfig, + J: SWCurveConfig, T: PlonkTranscript>, { verifier: &'a RingVerifier, J, T>, @@ -61,7 +61,7 @@ impl MultiRingBatchVerifier { result: Affine, ) -> PreparedMultiRingItem<'a, E, J, T> where - J: TECurveConfig, + J: SWCurveConfig, T: PlonkTranscript>, { let (challenges, mut rng) = verifier.plonk_verifier.restore_challenges( @@ -101,7 +101,7 @@ impl MultiRingBatchVerifier { /// 2. `push_prepared` - must be called sequentially (mutates the accumulator) pub fn push_prepared(&mut self, item: PreparedMultiRingItem<'_, E, J, T>) where - J: TECurveConfig, + J: SWCurveConfig, T: PlonkTranscript>, { let mut ts = item.verifier.plonk_verifier.transcript_prelude.clone(); @@ -117,7 +117,7 @@ impl MultiRingBatchVerifier { proof: RingProof>, result: Affine, ) where - J: TECurveConfig, + J: SWCurveConfig, T: PlonkTranscript>, { let item = Self::prepare(verifier, proof, result); diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index 9e2d1ba..d26eae7 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::short_weierstrass::{Affine, SWCurveConfig}; 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,7 +181,7 @@ impl VerifierKey> { } } -pub fn index, Curve: TECurveConfig>( +pub fn index, Curve: SWCurveConfig>( pcs_params: &CS::Params, piop_params: &PiopParams, keys: &[Affine], diff --git a/w3f-ring-proof/src/piop/params.rs b/w3f-ring-proof/src/piop/params.rs index 22bd21e..e980117 100644 --- a/w3f-ring-proof/src/piop/params.rs +++ b/w3f-ring-proof/src/piop/params.rs @@ -1,4 +1,4 @@ -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::{AdditiveGroup, AffineRepr, CurveGroup}; use ark_ff::{BigInteger, PrimeField}; use ark_std::{vec, vec::Vec}; @@ -10,7 +10,7 @@ use crate::piop::FixedColumns; /// Plonk Interactive Oracle Proofs (PIOP) parameters. #[derive(Clone)] -pub struct PiopParams> { +pub struct PiopParams> { /// Domain over which the piop is represented. pub(crate) domain: Domain, /// Number of bits used to represent a jubjub scalar. @@ -25,7 +25,7 @@ pub struct PiopParams> { pub(crate) padding: Affine, } -impl> PiopParams { +impl> PiopParams { /// Initialize PIOP parameters. /// /// - `domain`: polynomials evaluation domain. @@ -100,9 +100,9 @@ impl> PiopParams { #[cfg(test)] mod tests { - use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, EdwardsAffine, Fq, Fr}; - use ark_std::ops::Mul; + use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine, Fq, Fr}; use ark_std::{test_rng, UniformRand}; + use ark_std::ops::Mul; use w3f_plonk_common::domain::Domain; use w3f_plonk_common::test_helpers::cond_sum; @@ -112,9 +112,9 @@ mod tests { #[test] fn test_powers_of_h() { let rng = &mut test_rng(); - let h = EdwardsAffine::rand(rng); - let seed = EdwardsAffine::rand(rng); - let padding = EdwardsAffine::rand(rng); + let h = SWAffine::rand(rng); + let seed = SWAffine::rand(rng); + let padding = SWAffine::rand(rng); let domain = Domain::new(1024, false); let params = PiopParams::::setup(domain, h, seed, padding); diff --git a/w3f-ring-proof/src/piop/prover.rs b/w3f-ring-proof/src/piop/prover.rs index 07267c3..d0050d0 100644 --- a/w3f-ring-proof/src/piop/prover.rs +++ b/w3f-ring-proof/src/piop/prover.rs @@ -1,4 +1,4 @@ -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ff::PrimeField; use ark_poly::univariate::DensePolynomial; use ark_poly::Evaluations; @@ -22,7 +22,7 @@ use w3f_plonk_common::{Column, 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>, @@ -38,7 +38,7 @@ pub struct PiopProver> { cond_add_acc_y: FixedCells, } -impl> PiopProver { +impl> PiopProver { pub fn build( params: &PiopParams, fixed_columns: FixedColumns>, @@ -90,7 +90,7 @@ impl ProverPiop for PiopProver where F: PrimeField, C: Commitment, - Curve: TECurveConfig, + Curve: SWCurveConfig, { type Commitments = RingCommitments; type Evaluations = RingEvaluations; diff --git a/w3f-ring-proof/src/piop/verifier.rs b/w3f-ring-proof/src/piop/verifier.rs index 8eb663f..e5ec773 100644 --- a/w3f-ring-proof/src/piop/verifier.rs +++ b/w3f-ring-proof/src/piop/verifier.rs @@ -1,4 +1,4 @@ -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_std::marker::PhantomData; @@ -101,7 +101,7 @@ impl, P: AffineRepr> PiopVerifier } } -impl, Jubjub: TECurveConfig> VerifierPiop +impl, Jubjub: SWCurveConfig> VerifierPiop for PiopVerifier> { const N_CONSTRAINTS: usize = 7; diff --git a/w3f-ring-proof/src/ring.rs b/w3f-ring-proof/src/ring.rs index 600455d..a41c0a5 100644 --- a/w3f-ring-proof/src/ring.rs +++ b/w3f-ring-proof/src/ring.rs @@ -1,5 +1,5 @@ use ark_ec::pairing::Pairing; -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM}; use ark_ff::PrimeField; use ark_poly::EvaluationDomain; @@ -36,7 +36,7 @@ const IDLE_ROWS: usize = ZK_ROWS + 1; pub struct Ring< F: PrimeField, KzgCurve: Pairing, - VrfCurveConfig: TECurveConfig, + VrfCurveConfig: SWCurveConfig, > { /// KZG commitment to the x coordinates of the described vector. pub cx: KzgCurve::G1Affine, @@ -55,7 +55,7 @@ pub struct Ring< impl< F: PrimeField, KzgCurve: Pairing, - VrfCurveConfig: TECurveConfig, + VrfCurveConfig: SWCurveConfig, > fmt::Debug for Ring { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -70,7 +70,7 @@ impl< impl< F: PrimeField, KzgCurve: Pairing, - VrfCurveConfig: TECurveConfig, + VrfCurveConfig: SWCurveConfig, > Ring { /// Builds the commitment to the vector @@ -257,7 +257,7 @@ impl> RingBuilderKey| Ok(ring_builder_key.lis_in_g1[range].to_vec()); // piop params - let h = EdwardsAffine::rand(rng); - let seed = EdwardsAffine::rand(rng); - let padding = EdwardsAffine::rand(rng); + let h = SWAffine::rand(rng); + let seed = SWAffine::rand(rng); + let padding = SWAffine::rand(rng); let domain = Domain::new(domain_size, true); let piop_params = PiopParams::setup(domain, h, seed, padding); @@ -295,7 +295,7 @@ mod tests { assert_eq!(ring.cx, monimial_cx); assert_eq!(ring.cy, monimial_cy); - let keys = random_vec::(ring.max_keys, rng); + let keys = random_vec::(ring.max_keys, rng); ring.append(&keys, srs); let (monimial_cx, monimial_cy) = get_monomial_commitment(&pcs_params, &piop_params, &keys); assert_eq!(ring.cx, monimial_cx); @@ -316,9 +316,9 @@ mod tests { let srs = |range: Range| Ok(ring_builder_key.lis_in_g1[range].to_vec()); // piop params - let h = EdwardsAffine::rand(rng); - let seed = EdwardsAffine::rand(rng); - let padding = EdwardsAffine::rand(rng); + let h = SWAffine::rand(rng); + let seed = SWAffine::rand(rng); + let padding = SWAffine::rand(rng); let domain = Domain::new(domain_size, true); let piop_params = PiopParams::setup(domain, h, seed, padding); @@ -330,7 +330,7 @@ mod tests { fn get_monomial_commitment( pcs_params: &URS, piop_params: &PiopParams, - keys: &[EdwardsAffine], + keys: &[SWAffine], ) -> (G1Affine, G1Affine) { let (_, verifier_key) = crate::piop::index::<_, KZG, _>(pcs_params, piop_params, keys); diff --git a/w3f-ring-proof/src/ring_prover.rs b/w3f-ring-proof/src/ring_prover.rs index ac4db81..4428454 100644 --- a/w3f-ring-proof/src/ring_prover.rs +++ b/w3f-ring-proof/src/ring_prover.rs @@ -1,4 +1,4 @@ -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ff::PrimeField; use ark_std::{end_timer, start_timer}; use w3f_pcs::pcs::PCS; @@ -14,7 +14,7 @@ pub struct RingProver where F: PrimeField, CS: PCS, - Curve: TECurveConfig, + Curve: SWCurveConfig, T: PlonkTranscript, { piop_params: PiopParams, @@ -27,7 +27,7 @@ impl RingProver where F: PrimeField, CS: PCS, - Curve: TECurveConfig, + Curve: SWCurveConfig, T: PlonkTranscript, { pub fn init( diff --git a/w3f-ring-proof/src/ring_verifier.rs b/w3f-ring-proof/src/ring_verifier.rs index 9765b11..b2aef8a 100644 --- a/w3f-ring-proof/src/ring_verifier.rs +++ b/w3f-ring-proof/src/ring_verifier.rs @@ -1,5 +1,5 @@ use ark_ec::pairing::Pairing; -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_std::rand::RngCore; @@ -19,7 +19,7 @@ pub struct RingVerifier where F: PrimeField, CS: PCS, - Jubjub: TECurveConfig, + Jubjub: SWCurveConfig, T: PlonkTranscript, { pub(crate) piop_params: PiopParams, @@ -31,7 +31,7 @@ impl RingVerifier where F: PrimeField, CS: PCS, - Jubjub: TECurveConfig, + Jubjub: SWCurveConfig, T: PlonkTranscript, { pub fn init( @@ -99,7 +99,7 @@ where pub struct KzgBatchVerifier where E: Pairing, - J: TECurveConfig, + J: SWCurveConfig, T: PlonkTranscript>, { pub acc: KzgAccumulator, @@ -110,7 +110,7 @@ where pub struct PreparedBatchItem where E: Pairing, - J: TECurveConfig, + J: SWCurveConfig, { piop: PiopVerifier as PCS>::C, Affine>, proof: RingProof>, @@ -121,7 +121,7 @@ where impl KzgBatchVerifier where E: Pairing, - J: TECurveConfig, + J: SWCurveConfig, T: PlonkTranscript>, { /// Prepares a ring proof for batch verification without accumulating it. @@ -200,7 +200,7 @@ where impl RingVerifier, J, T> where E: Pairing, - J: TECurveConfig, + J: SWCurveConfig, T: PlonkTranscript>, { /// Build a new batch verifier. From 5f1bfae8abd15f9d5f32d37d83955af528ab5e40 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Thu, 9 Apr 2026 14:50:14 +0300 Subject: [PATCH 02/36] fmt --- w3f-ring-proof/benches/ring_proof.rs | 2 +- w3f-ring-proof/src/lib.rs | 2 +- w3f-ring-proof/src/piop/params.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/w3f-ring-proof/benches/ring_proof.rs b/w3f-ring-proof/benches/ring_proof.rs index f9816d8..ac21ab6 100644 --- a/w3f-ring-proof/benches/ring_proof.rs +++ b/w3f-ring-proof/benches/ring_proof.rs @@ -2,7 +2,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criteri use ark_bls12_381::Bls12_381; use ark_ec::CurveGroup; -use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine, Fq, Fr}; +use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, Fq, Fr, SWAffine}; use ark_serialize::CanonicalSerialize; use ark_std::ops::Mul; use ark_std::rand::Rng; diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index c600c0f..512626b 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -53,7 +53,7 @@ impl ArkTranscript { mod tests { use ark_bls12_381::Bls12_381; use ark_ec::CurveGroup; - use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine, Fq, Fr}; + use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, Fq, Fr, SWAffine}; use ark_std::ops::Mul; use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, test_rng, UniformRand}; diff --git a/w3f-ring-proof/src/piop/params.rs b/w3f-ring-proof/src/piop/params.rs index e980117..37b9f39 100644 --- a/w3f-ring-proof/src/piop/params.rs +++ b/w3f-ring-proof/src/piop/params.rs @@ -100,9 +100,9 @@ impl> PiopParams { #[cfg(test)] mod tests { - use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine, Fq, Fr}; - use ark_std::{test_rng, UniformRand}; + use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, Fq, Fr, SWAffine}; use ark_std::ops::Mul; + use ark_std::{test_rng, UniformRand}; use w3f_plonk_common::domain::Domain; use w3f_plonk_common::test_helpers::cond_sum; From ddddbfefaf5be3994f3f23b0ebce09f2a9400474 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Thu, 9 Apr 2026 16:17:06 +0300 Subject: [PATCH 03/36] pasta-tree crate --- Cargo.toml | 14 +++++---- pasta-tree/Cargo.toml | 54 ++++++++++++++++++++++++++++++++++ pasta-tree/src/lib.rs | 14 +++++++++ w3f-ring-proof/Cargo.toml | 6 ++-- w3f-ring-proof/src/piop/mod.rs | 18 ++++++------ 5 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 pasta-tree/Cargo.toml create mode 100644 pasta-tree/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 72ebe25..c2b0144 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,26 @@ [workspace] resolver = "2" members = [ - # "evm-vrfier", + "pasta-tree", +# "evm-vrfier", "w3f-plonk-common", "w3f-ring-proof", - "w3f-ring-vrf-snark", +# "w3f-ring-vrf-snark", ] [workspace.dependencies] +w3f-pcs = { path = "../fflonk", default-features = false } +#w3f-pcs = { git = "https://github.com/paritytech/fflonk", branch = "ipa-pcs", default-features = false } +w3f-plonk-common = { path = "w3f-plonk-common", default-features = false } +#w3f-pcs = { version = "0.0.5", default-features = false } +#w3f-plonk-common = { version = "0.0.6", default-features = false } +ark-transcript = { version = "0.0.3", default-features = false } ark-std = { version = "0.5", default-features = false } ark-ff = { version = "0.5", default-features = false } ark-ec = { version = "0.5", default-features = false } ark-poly = { version = "0.5", default-features = false } ark-serialize = { version = "0.5", default-features = false, features = ["derive"] } -w3f-pcs = { version = "0.0.5", default-features = false } -w3f-plonk-common = { version = "0.0.6", default-features = false } rayon = { version = "1", default-features = false } -ark-transcript = { version = "0.0.3", default-features = false } blake2 = { version = "0.10", default-features = false } ark-bls12-381 = { version = "0.5", default-features = false, features = ["curve"] } ark-ed-on-bls12-381-bandersnatch = { version = "0.5", default-features = false } diff --git a/pasta-tree/Cargo.toml b/pasta-tree/Cargo.toml new file mode 100644 index 0000000..78919f8 --- /dev/null +++ b/pasta-tree/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "pasta-tree" +version = "0.0.1" +edition = "2024" +authors = ["Sergey Vasilyev "] +license = "MIT/Apache-2.0" +description = "Hiding Verkle Tree over Pasta Curves" +keywords = ["cryptography", "accumulator", "verkle", "ring-vrf"] +repository = "https://github.com/w3f/ring-proof" + +[dependencies] +w3f-pcs.workspace = true +w3f-plonk-common.workspace = true +w3f-ring-proof = { path = "../w3f-ring-proof" } +ark-pallas = { version = "0.5", default-features = false, features = ["curve"] } +ark-vesta = { version = "0.5", default-features = false } +ark-transcript.workspace = true +ark-std.workspace = true +ark-ff.workspace = true +ark-ec.workspace = true +ark-poly.workspace = true +ark-serialize.workspace = true +rayon = { workspace = true, optional = true } + +[dev-dependencies] +criterion.workspace = true + +[features] +default = [ "std" ] +std = [ + "ark-std/std", + "ark-ff/std", + "ark-ec/std", + "ark-poly/std", + "ark-serialize/std", + "w3f-pcs/std", + "w3f-plonk-common/std", + "w3f-ring-proof/std", +] +parallel = [ + "std", + "rayon", + "ark-std/parallel", + "ark-ff/parallel", + "ark-ec/parallel", + "ark-poly/parallel", + "w3f-pcs/parallel", + "w3f-plonk-common/parallel", + "w3f-ring-proof/parallel", +] +print-trace = [ + "ark-std/print-trace", +] +asm = [ "w3f-pcs/asm" ] \ No newline at end of file diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/pasta-tree/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/w3f-ring-proof/Cargo.toml b/w3f-ring-proof/Cargo.toml index 6f1fef5..06674a8 100644 --- a/w3f-ring-proof/Cargo.toml +++ b/w3f-ring-proof/Cargo.toml @@ -9,15 +9,15 @@ keywords = ["cryptography", "ring-vrf"] repository = "https://github.com/w3f/ring-proof" [dependencies] +w3f-pcs.workspace = true +w3f-plonk-common.workspace = true +ark-transcript.workspace = true ark-std.workspace = true ark-ff.workspace = true ark-ec.workspace = true ark-poly.workspace = true ark-serialize.workspace = true -w3f-pcs.workspace = true rayon = { workspace = true, optional = true } -w3f-plonk-common.workspace = true -ark-transcript.workspace = true [dev-dependencies] ark-bls12-381.workspace = true diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index d26eae7..5a8d3ac 100644 --- a/w3f-ring-proof/src/piop/mod.rs +++ b/w3f-ring-proof/src/piop/mod.rs @@ -5,7 +5,7 @@ use ark_ff::PrimeField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::marker::PhantomData; use ark_std::{vec, vec::Vec}; -use w3f_pcs::pcs::kzg::commitment::KzgCommitment; +use w3f_pcs::pcs::kzg::commitment::WrappedAffine; use w3f_pcs::pcs::kzg::params::RawKzgVerifierKey; use w3f_pcs::pcs::kzg::KZG; use w3f_pcs::pcs::{Commitment, PcsParams, PCS}; @@ -96,15 +96,15 @@ impl> FixedColumnsCommitted { } } -impl FixedColumnsCommitted> { - pub fn from_ring>( - ring: &Ring, +impl> FixedColumnsCommitted> { + pub fn from_ring, G: SWCurveConfig>( + ring: &Ring, ) -> Self { - let cx = KzgCommitment(ring.cx); - let cy = KzgCommitment(ring.cy); + let cx = WrappedAffine(ring.cx); + let cy = WrappedAffine(ring.cy); Self { points: [cx, cy], - ring_selector: KzgCommitment(ring.selector), + ring_selector: WrappedAffine(ring.selector), phantom: Default::default(), } } @@ -167,7 +167,7 @@ impl VerifierKey> { } pub fn from_commitment_and_kzg_vk( - commitment: FixedColumnsCommitted>, + commitment: FixedColumnsCommitted>, kzg_vk: RawKzgVerifierKey, ) -> Self { Self { @@ -176,7 +176,7 @@ impl VerifierKey> { } } - pub fn commitment(&self) -> FixedColumnsCommitted> { + pub fn commitment(&self) -> FixedColumnsCommitted> { self.fixed_columns_committed.clone() } } From 3ccf9d8771c483260c45d2fa3f15af88adfdd0fe Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Thu, 9 Apr 2026 16:24:25 +0300 Subject: [PATCH 04/36] test_setup --- w3f-ring-proof/src/lib.rs | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 512626b..7a35324 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -1,8 +1,10 @@ #![cfg_attr(not(feature = "std"), no_std)] +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ff::PrimeField; use ark_serialize::CanonicalSerialize; -use ark_std::rand::RngCore; +use ark_std::rand::{Rng, RngCore}; +use ark_std::UniformRand; use w3f_pcs::pcs::PCS; pub use piop::index; @@ -27,7 +29,7 @@ pub use w3f_pcs::pcs; pub struct ArkTranscript(ark_transcript::Transcript); impl> w3f_plonk_common::transcript::PlonkTranscript - for ArkTranscript +for ArkTranscript { fn _128_bit_point(&mut self, label: &'static [u8]) -> F { self.0.challenge(label).read_reduce() @@ -49,6 +51,17 @@ impl ArkTranscript { } } +pub fn test_setup, G: SWCurveConfig>(rng: &mut R, domain_size: usize) -> (CS::Params, PiopParams) { + let setup_degree = 3 * domain_size; + let pcs_params = CS::setup(setup_degree, rng); + let domain = Domain::new(domain_size, true); + let h = Affine::::rand(rng); + let seed = Affine::::rand(rng); + let padding = Affine::::rand(rng); + let piop_params = PiopParams::setup(domain, h, seed, padding); + (pcs_params, piop_params) +} + #[cfg(test)] mod tests { use ark_bls12_381::Bls12_381; @@ -77,7 +90,7 @@ mod tests { ) { let rng = &mut test_rng(); - let (pcs_params, piop_params) = setup::<_, CS>(rng, domain_size); + let (pcs_params, piop_params) = test_setup::<_, _, CS, BandersnatchConfig>(rng, domain_size); let keyset_size = piop_params.keyset_part_size; let pks = random_vec::(keyset_size, rng); let (prover_key, verifier_key) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); @@ -120,7 +133,7 @@ mod tests { let domain_size = 2usize.pow(9); - let (pcs_params, piop_params) = setup::<_, KZG>(rng, domain_size); + let (pcs_params, piop_params) = test_setup::<_, Fq, KZG, BandersnatchConfig>(rng, domain_size); let ring_builder_key = RingBuilderKey::from_srs(&pcs_params, domain_size); let max_keyset_size = piop_params.keyset_part_size; @@ -138,22 +151,6 @@ mod tests { ); } - fn setup>( - rng: &mut R, - domain_size: usize, - ) -> (CS::Params, PiopParams) { - let setup_degree = 3 * domain_size; - let pcs_params = CS::setup(setup_degree, rng); - - let domain = Domain::new(domain_size, true); - let h = SWAffine::rand(rng); - let seed = SWAffine::rand(rng); - let padding = SWAffine::rand(rng); - let piop_params = PiopParams::setup(domain, h, seed, padding); - - (pcs_params, piop_params) - } - // cargo test test_ring_proof_kzg --release --features="print-trace" -- --show-output // // Batch vs sequential verification times (ms): @@ -193,7 +190,7 @@ mod tests { let domain_size = 2usize.pow(9); let proofs_per_ring = 4; - let (pcs_params, piop_params) = setup::<_, KZG>(rng, domain_size); + let (pcs_params, piop_params) = test_setup::<_, Fq, KZG, BandersnatchConfig>(rng, domain_size); // Ring A let keyset_size_a = piop_params.keyset_part_size; From 587235847222b27737bc128cf69e9731eede3798 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Thu, 9 Apr 2026 16:51:20 +0300 Subject: [PATCH 05/36] pasta ring works --- pasta-tree/src/lib.rs | 43 ++++++++++++++++++++++++++++--- w3f-ring-proof/src/piop/params.rs | 2 +- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index b93cf3f..c02d888 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -4,11 +4,46 @@ pub fn add(left: u64, right: u64) -> u64 { #[cfg(test)] mod tests { - use super::*; + use ark_ec::CurveGroup; + use ark_std::rand::Rng; + use ark_std::{end_timer, start_timer, test_rng, UniformRand}; + use w3f_pcs::pcs::ipa::IPA; + use w3f_plonk_common::test_helpers::random_vec; + use w3f_ring_proof::ring_prover::RingProver; + use w3f_ring_proof::{index, test_setup, ArkTranscript}; + use w3f_ring_proof::ring_verifier::RingVerifier; #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + fn test_pasta_ring() { + let rng = &mut test_rng(); + + let (pcs_params, piop_params) = test_setup::<_, _, IPA, ark_vesta::VestaConfig>(rng, 512); + let keyset_size = piop_params.keyset_part_size; + let pks = random_vec::(keyset_size, rng); + let (prover_key, verifier_key) = index::<_, IPA, _>(&pcs_params, &piop_params, &pks); + + let t_prove = start_timer!(|| "Prove"); + let prover_idx = rng.gen_range(0..keyset_size); + let prover = RingProver::init( + prover_key.clone(), + piop_params.clone(), + prover_idx, + ArkTranscript::new(b"w3f-ring-proof-test"), + ); + let prover_pk = pks[prover_idx].clone(); + let blinding_factor = ark_vesta::Fr::rand(rng); + let blinded_pk = prover_pk + piop_params.h * blinding_factor; + let blinded_pk = blinded_pk.into_affine(); + let proof = prover.prove(blinding_factor); + end_timer!(t_prove); + + let ring_verifier = RingVerifier::init( + verifier_key, + piop_params, + ArkTranscript::new(b"w3f-ring-proof-test"), + ); + let t_verify = start_timer!(|| "Verify"); + assert!(ring_verifier.verify(proof, blinded_pk)); + end_timer!(t_verify); } } diff --git a/w3f-ring-proof/src/piop/params.rs b/w3f-ring-proof/src/piop/params.rs index 37b9f39..31eae71 100644 --- a/w3f-ring-proof/src/piop/params.rs +++ b/w3f-ring-proof/src/piop/params.rs @@ -18,7 +18,7 @@ pub struct PiopParams> { /// Length of the part of the column representing the public keys (including the padding). pub keyset_part_size: usize, /// Blinding base point. - pub(crate) h: Affine, + pub h: Affine, //TODO: make a method /// Summation base point. pub(crate) seed: Affine, /// The point used to pad the list of public keys. From f7b07315e210a41cf5a0ee1771bbf35e1a41fd8d Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 10 Apr 2026 03:00:41 +0300 Subject: [PATCH 06/36] Cargo.tomls cleaned up --- pasta-tree/Cargo.toml | 8 +++----- w3f-ring-proof/Cargo.toml | 5 +---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pasta-tree/Cargo.toml b/pasta-tree/Cargo.toml index 78919f8..37f94ea 100644 --- a/pasta-tree/Cargo.toml +++ b/pasta-tree/Cargo.toml @@ -26,7 +26,7 @@ rayon = { workspace = true, optional = true } criterion.workspace = true [features] -default = [ "std" ] +default = ["std"] std = [ "ark-std/std", "ark-ff/std", @@ -48,7 +48,5 @@ parallel = [ "w3f-plonk-common/parallel", "w3f-ring-proof/parallel", ] -print-trace = [ - "ark-std/print-trace", -] -asm = [ "w3f-pcs/asm" ] \ No newline at end of file +print-trace = ["ark-std/print-trace", ] +asm = ["w3f-pcs/asm"] \ No newline at end of file diff --git a/w3f-ring-proof/Cargo.toml b/w3f-ring-proof/Cargo.toml index 06674a8..f488ec1 100644 --- a/w3f-ring-proof/Cargo.toml +++ b/w3f-ring-proof/Cargo.toml @@ -49,9 +49,6 @@ parallel = [ "w3f-plonk-common/parallel", "w3f-pcs/parallel" ] -print-trace = [ - "ark-std/print-trace", - "w3f-plonk-common/print-trace" -] +print-trace = ["ark-std/print-trace"] asm = [ "w3f-pcs/asm" ] test-vectors = [ "w3f-plonk-common/test-vectors" ] From a3d2683f8813fa08c7c7b7f1bc8b4b630f767b74 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 10 Apr 2026 04:41:03 +0300 Subject: [PATCH 07/36] stuff made pub mostly --- w3f-plonk-common/src/domain.rs | 2 +- w3f-plonk-common/src/prover.rs | 18 +++++++++++++++--- w3f-ring-proof/src/lib.rs | 6 +++--- w3f-ring-proof/src/piop/mod.rs | 16 ++++++++-------- w3f-ring-proof/src/piop/params.rs | 2 +- w3f-ring-proof/src/ring_prover.rs | 3 --- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/w3f-plonk-common/src/domain.rs b/w3f-plonk-common/src/domain.rs index 42241dc..c961bd5 100644 --- a/w3f-plonk-common/src/domain.rs +++ b/w3f-plonk-common/src/domain.rs @@ -95,7 +95,7 @@ impl Domain { } } - pub(crate) fn divide_by_vanishing_poly(&self, poly: &DensePolynomial) -> DensePolynomial { + pub fn divide_by_vanishing_poly(&self, poly: &DensePolynomial) -> DensePolynomial { let (quotient, remainder) = if self.hiding { let exclude_zk_rows = poly * self.zk_rows_vanishing_poly.as_ref().unwrap(); exclude_zk_rows.divide_by_vanishing_poly(self.domains.x1) diff --git a/w3f-plonk-common/src/prover.rs b/w3f-plonk-common/src/prover.rs index 6dc96be..c221191 100644 --- a/w3f-plonk-common/src/prover.rs +++ b/w3f-plonk-common/src/prover.rs @@ -1,7 +1,7 @@ use ark_ff::PrimeField; use ark_poly::{Evaluations, Polynomial}; use ark_serialize::CanonicalSerialize; -use ark_std::vec; +use ark_std::{end_timer, start_timer, vec}; use w3f_pcs::aggregation::single::aggregate_polys; use w3f_pcs::pcs::PCS; @@ -40,7 +40,13 @@ impl, T: PlonkTranscript> PlonkProver transcript.add_instance(&piop.result()); // ROUND 1 // The prover commits to the columns. - let column_commitments = piop.committed_columns(|p| CS::commit(&self.pcs_ck, p).unwrap()); + + let column_commitments = piop.committed_columns(|p| { + let _t_commit_col = start_timer!(|| format!("Committing to deg(f)={}", p.degree())); + let c = CS::commit(&self.pcs_ck, p).unwrap(); + end_timer!(_t_commit_col); + c + }); transcript.add_committed_cols(&column_commitments); // ROUND 2 @@ -52,7 +58,9 @@ impl, T: PlonkTranscript> PlonkProver let agg_constraint_poly = agg_constraint_poly.interpolate(); let quotient_poly = piop.domain().divide_by_vanishing_poly(&agg_constraint_poly); // The prover commits to the quotient polynomial... + let _t_commit_q = start_timer!(|| format!("Committing to deg(f)={}", quotient_poly.degree())); let quotient_commitment = CS::commit(&self.pcs_ck, "ient_poly).unwrap(); + end_timer!(_t_commit_q); transcript.add_quotient_commitment("ient_commitment); // and receives the evaluation point in response @@ -71,8 +79,12 @@ impl, T: PlonkTranscript> PlonkProver let polys_at_zeta = [columns_to_open, vec![quotient_poly]].concat(); let nus = transcript.get_kzg_aggregation_challenges(polys_at_zeta.len()); let agg_at_zeta = aggregate_polys(&polys_at_zeta, &nus); + let _t_open_zeta = start_timer!(|| format!("Opening deg(f)={}", agg_at_zeta.degree())); let agg_at_zeta_proof = CS::open(&self.pcs_ck, &agg_at_zeta, zeta).unwrap(); + end_timer!(_t_open_zeta); + let _t_open_zeta_omega = start_timer!(|| format!("Opening deg(f)={}", lin.degree())); let lin_at_zeta_omega_proof = CS::open(&self.pcs_ck, &lin, zeta_omega).unwrap(); + end_timer!(_t_open_zeta_omega); Proof { column_commitments, quotient_commitment, @@ -83,7 +95,7 @@ impl, T: PlonkTranscript> PlonkProver } } - fn aggregate_evaluations(polys: &[Evaluations], coeffs: &[F]) -> Evaluations { + pub fn aggregate_evaluations(polys: &[Evaluations], coeffs: &[F]) -> Evaluations { assert_eq!(coeffs.len(), polys.len()); polys .iter() diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 7a35324..11e6ada 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -15,7 +15,7 @@ pub use crate::piop::{params::PiopParams, FixedColumnsCommitted, ProverKey, Veri use crate::piop::{RingCommitments, RingEvaluations}; pub mod multi_ring_batch_verifier; -mod piop; +pub mod piop; pub mod ring; pub mod ring_prover; pub mod ring_verifier; @@ -171,8 +171,8 @@ mod tests { // Batch verification scales sub-linearly. #[test] fn test_ring_proof_kzg() { - let batch_size: usize = 16; - let (verifier, claims) = _test_ring_proof::>(2usize.pow(10), batch_size); + let batch_size: usize = 1; + let (verifier, claims) = _test_ring_proof::>(2usize.pow(9), batch_size); let t_verify_batch = start_timer!(|| format!("Verify Batch KZG (batch={batch_size})")); let (blinded_pks, proofs) = claims.into_iter().unzip(); assert!(verifier.verify_batch_kzg(proofs, blinded_pks)); diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index 5a8d3ac..16d8d75 100644 --- a/w3f-ring-proof/src/piop/mod.rs +++ b/w3f-ring-proof/src/piop/mod.rs @@ -19,8 +19,8 @@ use crate::ring::Ring; use crate::PiopParams; pub mod params; -mod prover; -mod verifier; +pub mod prover; +pub mod verifier; #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct RingCommitments> { @@ -87,7 +87,7 @@ pub struct FixedColumnsCommitted> { } impl> FixedColumnsCommitted { - fn as_vec(&self) -> Vec { + pub fn as_vec(&self) -> Vec { vec![ self.points[0].clone(), self.points[1].clone(), @@ -127,9 +127,9 @@ impl> FixedColumns { #[derive(CanonicalSerialize, CanonicalDeserialize)] pub struct ProverKey, G: AffineRepr> { - pub(crate) pcs_ck: CS::CK, - pub(crate) fixed_columns: FixedColumns, - pub(crate) verifier_key: VerifierKey, // used in the Fiat-Shamir transform + pub pcs_ck: CS::CK, + pub fixed_columns: FixedColumns, + pub verifier_key: VerifierKey, // used in the Fiat-Shamir transform } impl, G: AffineRepr> Clone for ProverKey { @@ -144,8 +144,8 @@ impl, G: AffineRepr> Clone for ProverKe #[derive(Debug, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct VerifierKey> { - pub(crate) pcs_raw_vk: ::RVK, - pub(crate) fixed_columns_committed: FixedColumnsCommitted, + pub pcs_raw_vk: ::RVK, + pub fixed_columns_committed: FixedColumnsCommitted, //TODO: domain } diff --git a/w3f-ring-proof/src/piop/params.rs b/w3f-ring-proof/src/piop/params.rs index 31eae71..a0ffb86 100644 --- a/w3f-ring-proof/src/piop/params.rs +++ b/w3f-ring-proof/src/piop/params.rs @@ -12,7 +12,7 @@ use crate::piop::FixedColumns; #[derive(Clone)] pub struct PiopParams> { /// Domain over which the piop is represented. - pub(crate) domain: Domain, + pub domain: Domain, /// Number of bits used to represent a jubjub scalar. pub(crate) scalar_bitlen: usize, /// Length of the part of the column representing the public keys (including the padding). diff --git a/w3f-ring-proof/src/ring_prover.rs b/w3f-ring-proof/src/ring_prover.rs index 4428454..5e951b2 100644 --- a/w3f-ring-proof/src/ring_prover.rs +++ b/w3f-ring-proof/src/ring_prover.rs @@ -1,6 +1,5 @@ use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ff::PrimeField; -use ark_std::{end_timer, start_timer}; use w3f_pcs::pcs::PCS; use w3f_plonk_common::prover::PlonkProver; @@ -53,9 +52,7 @@ where } pub fn prove(&self, t: Curve::ScalarField) -> RingProof { - let t_witgen = start_timer!(|| "witgen"); let piop = PiopProver::build(&self.piop_params, self.fixed_columns.clone(), self.k, t); - end_timer!(t_witgen); self.plonk_prover.prove(piop) } From 20cb45195b8f3ae5c7c237847b2ec8795e5cd897 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 10 Apr 2026 04:41:18 +0300 Subject: [PATCH 08/36] shplonk openning --- pasta-tree/src/lib.rs | 154 +++++++++++++++++++++++++++++++++++------- 1 file changed, 131 insertions(+), 23 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index c02d888..39e0f2d 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -5,45 +5,153 @@ pub fn add(left: u64, right: u64) -> u64 { #[cfg(test)] mod tests { use ark_ec::CurveGroup; + use ark_ff::PrimeField; + use ark_poly::Polynomial; + use ark_std::iterable::Iterable; use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, test_rng, UniformRand}; + use ark_vesta::VestaConfig; + use std::collections::BTreeSet; + use w3f_pcs::aggregation::multiple::Transcript; use w3f_pcs::pcs::ipa::IPA; + use w3f_pcs::pcs::kzg::commitment::WrappedAffine; + use w3f_pcs::pcs::{RawVerifierKey, PCS}; + use w3f_pcs::shplonk::Shplonk; + use w3f_plonk_common::piop::ProverPiop; + use w3f_plonk_common::prover::PlonkProver; use w3f_plonk_common::test_helpers::random_vec; + use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ring_prover::RingProver; - use w3f_ring_proof::{index, test_setup, ArkTranscript}; use w3f_ring_proof::ring_verifier::RingVerifier; + use w3f_ring_proof::{index, test_setup, ArkTranscript}; + + type PallasIPA = IPA; + type PallasC = WrappedAffine; + // cargo test test_pasta_ring_plonk --release --features="print-trace" -- --show-output #[test] - fn test_pasta_ring() { + fn test_pasta_ring_plonk() { let rng = &mut test_rng(); - let (pcs_params, piop_params) = test_setup::<_, _, IPA, ark_vesta::VestaConfig>(rng, 512); + // setup + let domain_size = 2usize.pow(9); + let (pcs_params, piop_params) = test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); let keyset_size = piop_params.keyset_part_size; let pks = random_vec::(keyset_size, rng); - let (prover_key, verifier_key) = index::<_, IPA, _>(&pcs_params, &piop_params, &pks); - - let t_prove = start_timer!(|| "Prove"); - let prover_idx = rng.gen_range(0..keyset_size); - let prover = RingProver::init( - prover_key.clone(), - piop_params.clone(), - prover_idx, - ArkTranscript::new(b"w3f-ring-proof-test"), + let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); + let blinding = ark_vesta::Fr::rand(rng); + let pk_idx = rng.gen_range(0..keyset_size); + let blinded_pk = { + let prover_pk = pks[pk_idx].clone(); + let blinded_pk = prover_pk + piop_params.h * blinding; + blinded_pk.into_affine() + }; + + // prover + let fs = ArkTranscript::new(b"pasta-ring-proof-test"); + let prover = RingProver::init(prover_key, piop_params.clone(), pk_idx, fs.clone()); + let t_prove = start_timer!(|| format!("Proving IPA ring-proof with plonk, domain_size={domain_size}, keyset_size={keyset_size}")); + let proof = prover.prove(blinding); + end_timer!(t_prove); + + // verifier + let ring_verifier = RingVerifier::init(verifier_key, piop_params, fs); + let t_verify = start_timer!(|| "Verifying IPA plonk opening"); + let valid = ring_verifier.verify(proof, blinded_pk); + end_timer!(t_verify); + assert!(valid); + } + + struct Coeffs(F, F); + impl> Transcript for Coeffs { + fn get_gamma(&mut self) -> F { + self.0 + } + + fn commit_to_q(&mut self, _q: &CS::C) {} + + fn get_zeta(&mut self) -> F { + self.1 + } + } + + // cargo test test_pasta_ring_shplonk --release --features="print-trace" -- --show-output + #[test] + fn test_pasta_ring_shplonk() { + let rng = &mut test_rng(); + + // setup + let domain_size = 2usize.pow(9); + let (pcs_params, piop_params) = test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); + let keyset_size = piop_params.keyset_part_size; + let pks = random_vec::(keyset_size, rng); + let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); + let blinding = ark_vesta::Fr::rand(rng); + let pk_idx = rng.gen_range(0..keyset_size); + // let blinded_pk = { + // let prover_pk = pks[pk_idx].clone(); + // let blinded_pk = prover_pk + piop_params.h * blinding; + // blinded_pk.into_affine() + // }; + let pcs_ck = prover_key.pcs_ck; + let pcs_vk = verifier_key.pcs_raw_vk.prepare(); + + // prover + let piop = PiopProver::::build(&piop_params, prover_key.fixed_columns.clone(), pk_idx, blinding); + let t_prove = start_timer!(|| format!("Proving IPA ring-proof with shplonk, domain_size={domain_size}, keyset_size={keyset_size}")); + let zeta = ark_pallas::Fr::rand(rng); + let columns = as ProverPiop>::columns(&piop); + let (quotient, agg_lin) = { + let constraints = as ProverPiop>::constraints(&piop); + let alphas: Vec<_> = (0..constraints.len()).map(|_| ark_pallas::Fr::rand(rng)).collect(); + let agg_constraint_poly = PlonkProver::::aggregate_evaluations(&constraints, &alphas).interpolate(); + let quotient = piop_params.domain.divide_by_vanishing_poly(&agg_constraint_poly); + let constraints_lin = as ProverPiop>::constraints_lin(&piop, &zeta); + let agg_lin = w3f_pcs::aggregation::single::aggregate_polys(&constraints_lin, &alphas); + (quotient, agg_lin) + }; + + let mut polys = columns; + polys.push(quotient); + let mut coord_vecs = vec![vec![zeta]; polys.len()]; + polys.push(agg_lin.clone()); + coord_vecs.push(vec![zeta * piop_params.domain.omega()]); + + // commitments + let mut poly_cs = verifier_key.fixed_columns_committed.as_vec(); + let t_commit = start_timer!(|| format!("Commiting to {} columns of degree = {} and the quotient of degree = {}", polys.len()-5, polys[3].degree(), polys[7].degree())); + // skip the instance columns and the linearirization polynomial `agg_lin` + poly_cs.extend(polys[3..polys.len() - 1].iter().map(|p| PallasIPA::commit(&pcs_ck, p).unwrap())); + end_timer!(t_commit); + poly_cs.push(PallasIPA::commit(&pcs_ck, &agg_lin).unwrap()); + + let coord_sets: Vec> = coord_vecs.iter().cloned().map(BTreeSet::from_iter).collect(); + let vals: Vec<_> = polys.iter().zip(coord_vecs.iter()) + .map(|(f, xs)| xs.iter().map(|x| f.evaluate(&x)).collect::>()) + .collect(); + + let transcript = &mut Coeffs(ark_pallas::Fr::rand(rng), ark_pallas::Fr::rand(rng)); + let t_open = start_timer!(|| format!("Opening IPA ring-proof with shplonk, {} polys, max_degree = {}", polys.len(), polys[7].degree())); + let proof = Shplonk::::open_many( + &pcs_ck, + &polys, + &coord_sets, + transcript, ); - let prover_pk = pks[prover_idx].clone(); - let blinding_factor = ark_vesta::Fr::rand(rng); - let blinded_pk = prover_pk + piop_params.h * blinding_factor; - let blinded_pk = blinded_pk.into_affine(); - let proof = prover.prove(blinding_factor); + end_timer!(t_open); end_timer!(t_prove); - let ring_verifier = RingVerifier::init( - verifier_key, - piop_params, - ArkTranscript::new(b"w3f-ring-proof-test"), + // verifier + let t_verify = start_timer!(|| "Verifying IPA shplonk opening"); + let valid = Shplonk::::verify_many( + &pcs_vk, + &poly_cs, + proof, + &coord_vecs, + &vals, + transcript, ); - let t_verify = start_timer!(|| "Verify"); - assert!(ring_verifier.verify(proof, blinded_pk)); end_timer!(t_verify); + assert!(valid); } } From d37d0e3f912cc4666effb731bf7f63630281e2f4 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 10 Apr 2026 14:57:42 +0300 Subject: [PATCH 09/36] cosmetic --- pasta-tree/src/lib.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 39e0f2d..523229c 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -4,7 +4,6 @@ pub fn add(left: u64, right: u64) -> u64 { #[cfg(test)] mod tests { - use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::Polynomial; use ark_std::iterable::Iterable; @@ -41,18 +40,15 @@ mod tests { let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); let blinding = ark_vesta::Fr::rand(rng); let pk_idx = rng.gen_range(0..keyset_size); - let blinded_pk = { - let prover_pk = pks[pk_idx].clone(); - let blinded_pk = prover_pk + piop_params.h * blinding; - blinded_pk.into_affine() - }; + let blinded_pk = piop_params.blind_pk(pks[pk_idx], blinding); // prover let fs = ArkTranscript::new(b"pasta-ring-proof-test"); - let prover = RingProver::init(prover_key, piop_params.clone(), pk_idx, fs.clone()); + let prover = RingProver::init(prover_key, piop_params.clone(), 0, fs.clone()); let t_prove = start_timer!(|| format!("Proving IPA ring-proof with plonk, domain_size={domain_size}, keyset_size={keyset_size}")); - let proof = prover.prove(blinding); + let (blinded_pk_, proof) = prover.rerandomize_pk(pk_idx, blinding); end_timer!(t_prove); + assert_eq!(blinded_pk_, blinded_pk); // verifier let ring_verifier = RingVerifier::init(verifier_key, piop_params, fs); From 1c17388ce1f2a105d697606390afefc94ab6ccab Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Thu, 16 Apr 2026 17:30:55 +0300 Subject: [PATCH 10/36] folding fun --- pasta-tree/Cargo.toml | 1 + pasta-tree/src/lib.rs | 235 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 234 insertions(+), 2 deletions(-) diff --git a/pasta-tree/Cargo.toml b/pasta-tree/Cargo.toml index 37f94ea..1684883 100644 --- a/pasta-tree/Cargo.toml +++ b/pasta-tree/Cargo.toml @@ -23,6 +23,7 @@ ark-serialize.workspace = true rayon = { workspace = true, optional = true } [dev-dependencies] +ark-bls12-381.workspace = true criterion.workspace = true [features] diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 523229c..60dd3a5 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -4,11 +4,20 @@ pub fn add(left: u64, right: u64) -> u64 { #[cfg(test)] mod tests { + use ark_ec::scalar_mul::glv::GLVConfig; + use w3f_pcs::pcs::PcsParams; + use ark_ec::scalar_mul::wnaf::WnafContext; + use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; + use ark_ec::AdditiveGroup; + use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; + use ark_ff::{BigInteger, Field, Zero}; + use ark_pallas::PallasConfig; + use ark_poly::DenseUVPolynomial; use ark_poly::Polynomial; use ark_std::iterable::Iterable; use ark_std::rand::Rng; - use ark_std::{end_timer, start_timer, test_rng, UniformRand}; + use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; use std::collections::BTreeSet; use w3f_pcs::aggregation::multiple::Transcript; @@ -24,6 +33,10 @@ mod tests { use w3f_ring_proof::ring_verifier::RingVerifier; use w3f_ring_proof::{index, test_setup, ArkTranscript}; + #[cfg(feature = "parallel")] + use rayon::prelude::*; + use w3f_pcs::Poly; + type PallasIPA = IPA; type PallasC = WrappedAffine; @@ -115,7 +128,7 @@ mod tests { // commitments let mut poly_cs = verifier_key.fixed_columns_committed.as_vec(); - let t_commit = start_timer!(|| format!("Commiting to {} columns of degree = {} and the quotient of degree = {}", polys.len()-5, polys[3].degree(), polys[7].degree())); + let t_commit = start_timer!(|| format!("Commiting to {} columns of degree = {} and the quotient of degree = {}", polys.len()-5, polys[3].degree(), polys[7].degree())); // skip the instance columns and the linearirization polynomial `agg_lin` poly_cs.extend(polys[3..polys.len() - 1].iter().map(|p| PallasIPA::commit(&pcs_ck, p).unwrap())); end_timer!(t_commit); @@ -150,4 +163,222 @@ mod tests { end_timer!(t_verify); assert!(valid); } + + fn _bench_msm(log_n: u32) { + let rng = &mut test_rng(); + let n = 2usize.pow(log_n); + let (scalars, bases): (Vec<_>, Vec<_>) = (0..n).map(|_| (C::ScalarField::rand(rng), C::Affine::rand(rng))).unzip(); + let t_msm = start_timer!(|| format!("log(n)={log_n}, MSM on {}", ark_std::any::type_name::())); + let _res = C::msm(&bases, &scalars); + end_timer!(t_msm); + } + + // cargo test bench_msms --release --features="print-trace" -- --show-output + // qcargo test bench_msms --release --features="parallel print-trace" -- --show-output + #[test] + fn bench_msms() { + let log_n = 9; + + _bench_msm::(log_n); + _bench_msm::(log_n + 1); + // _bench_msm::(log_n); + // _bench_msm::(log_n); + // _bench_folding::(log_n); + // _bench_folding::(log_n + 1); + _bench_folding(log_n); + _bench_folding(log_n + 1); + + let rng = &mut test_rng(); + let n = 2usize.pow(log_n); + + let n3 = 3 * n; + let pcs_params = PallasIPA::setup(n3, rng); + + let p = Poly::::rand(n, rng); + let t_ipa_commit = start_timer!(|| format!("IPA commitment to a degree {n} polynomial")); + let _c = PallasIPA::commit(&pcs_params.ck(), &p); + end_timer!(t_ipa_commit); + + let p = Poly::::rand(n3, rng); + let t_ipa_commit = start_timer!(|| format!("IPA commitment to a degree 3*{n} polynomial")); + let _c = PallasIPA::commit(&pcs_params.ck(), &p); + end_timer!(t_ipa_commit); + } + + fn mul_endo_wnaf(p: ark_pallas::Projective, k1: (bool, ark_pallas::Fr), k2: (bool, ark_pallas::Fr)) -> ark_pallas::Projective { + let mut p1 = p; + let mut p2 = PallasConfig::endomorphism(&p); + if !k1.0 { + p1 = -p1; + } + if !k2.0 { + p2 = -p2; + } + let w_size = 4; + let wnaf = WnafContext::new(w_size); + let p1_table = wnaf.table(p1); + let p2_table = wnaf.table(p2); + let k1_wnaf = k1.1.into_bigint().find_wnaf(w_size).unwrap(); + let mut k2_wnaf = k2.1.into_bigint().find_wnaf(w_size).unwrap(); + k2_wnaf.resize(k1_wnaf.len(), 0); + + let mut result = ark_pallas::Projective::zero(); + let mut found_non_zero = false; + for (n1, n2) in k1_wnaf.into_iter().zip(k2_wnaf).rev() { + if found_non_zero { + result.double_in_place(); + } + + if n1 != 0 || n2 != 0 { + found_non_zero = true; + if n1 > 0 { + result += &p1_table[(n1 / 2) as usize]; + } + if n1 < 0 { + result -= &p1_table[((-n1) / 2) as usize]; + } + if n2 > 0 { + result += &p2_table[(n2 / 2) as usize]; + } + if n2 < 0 { + result -= &p2_table[((-n2) / 2) as usize]; + } + } + } + result + } + + fn _bench_folding(log_n: u32) { + let rng = &mut test_rng(); + let n = 2usize.pow(log_n); + let (l, r): (Vec, Vec) = (0..n).map(|_| (ark_pallas::Affine::rand(rng), ark_pallas::Affine::rand(rng))).unzip(); + let x = ark_pallas::Fr::rand(rng); + let _timer = start_timer!(|| format!("Naive folding, log(n) = {log_n}")); + let res: Vec = ark_std::cfg_iter!(l).zip(r.clone()) + .map(|(l, r)| r * x + l) + .collect(); + end_timer!(_timer); + + let _timer = start_timer!(|| format!("Naive folding with endo, log(n) = {log_n}")); + let res_: Vec = ark_std::cfg_into_iter!(l.clone()).zip(ark_std::cfg_into_iter!(r.clone())) + .map(|(l, r)| l + ::glv_mul_affine(r, x)) + .collect(); + end_timer!(_timer); + assert_eq!(res_, res); + + let _timer = start_timer!(|| format!("Naive folding with endo and w-NAF, log(n) = {log_n}")); + let ((sgn_k1, k1), (sgn_k2, k2)) = PallasConfig::scalar_decomposition(x); + let res_: Vec = ark_std::cfg_into_iter!(l).zip(ark_std::cfg_iter!(r)) + .map(|(l, r)| l + mul_endo_wnaf(r.into_group(), (sgn_k1, k1), (sgn_k2, k2))) + .collect(); + end_timer!(_timer); + assert_eq!(res_, res); + } + + fn batch_double_affine(bases: Vec>) -> Vec> { + let mut denoms: Vec = ark_std::cfg_iter!(bases) + .map(|p| p.y + p.y) + .collect(); + + ark_ff::batch_inversion(&mut denoms); + + ark_std::cfg_iter!(bases).zip(denoms).map(|(p, _2y_inv)| { + let (x, y) = p.xy().unwrap(); + let t = _2y_inv * (x.square() * C::BaseField::from(3) + ::COEFF_A); // (3x^2 + a) / 2y + let x_n = t.square() - x - x; + let y_n = t * (x - x_n) - y; + Affine::::new_unchecked(x_n, y_n) + }).collect() + } + + fn batch_double_affine_in_place(bases: &mut [Affine]) { + let three = C::BaseField::from(3); + let sw_a = ::COEFF_A; + let mut denoms: Vec = ark_std::cfg_iter!(bases) + .map(|p| p.y + p.y) + .collect(); + + ark_ff::batch_inversion(&mut denoms); + // ark_ff::batch_inversion_and_mul(&mut denoms, &C::BaseField::one()); + + cfg_iter_mut!(bases).zip(ark_std::cfg_into_iter!(denoms)) + .for_each(|(p, _2y_inv)| { + let t = _2y_inv * (p.x.square() * three + sw_a); // (3x^2 + a) / 2y + let old_x = p.x; + p.x = t.square() - p.x - p.x; + p.y = t * (old_x - p.x) - p.y; + }) + } + + fn batch_add_affine(bases1: Vec>, bases2: Vec>) -> Vec> { + let mut denoms: Vec = ark_std::cfg_iter!(bases1) + .zip(ark_std::cfg_iter!(bases2)) + .map(|(p1, p2)| p2.x - p1.x) + .collect(); + + ark_ff::batch_inversion(&mut denoms); + + ark_std::cfg_iter!(bases1) + .zip(ark_std::cfg_iter!(bases2)) + .zip(ark_std::cfg_iter!(denoms)) + .map(|((p1, p2), _x2_m_x1)| { + let (x1, y1) = p1.xy().unwrap(); + let (x2, y2) = p2.xy().unwrap(); + let t = (y2 - y1) * _x2_m_x1; + let x_n = t.square() - x1 - x2; + let y_n = t * (x1 - x_n) - y1; + Affine::::new_unchecked(x_n, y_n) + }).collect() + } + + fn batch_mul_by_x_affine(bases: Vec>, x: C::ScalarField) -> Vec> { + let mut res: Vec> = bases.clone(); + for b in ark_ff::BitIteratorBE::without_leading_zeros(x.into_bigint()).skip(1) { + batch_double_affine_in_place(&mut res); + if b { + res = batch_add_affine(res, bases.clone()); + } + } + res + } + + #[test] + fn bench_folding() { + let rng = &mut test_rng(); + let log_n = 10; + _bench_folding(log_n); + + let n = 2usize.pow(log_n); + let bases: Vec<_> = (0..n).map(|_| ark_pallas::Affine::rand(rng)).collect(); + let x = ark_pallas::Fr::rand(rng); + let dbl: Vec<_> = bases.iter().map(|p| { + let mut p = p.into_group(); + p.double_in_place(); + p.into_affine() + }).collect(); + assert_eq!(dbl, batch_double_affine(bases.clone())); + + let bases2: Vec<_> = (0..n).map(|_| ark_pallas::Affine::rand(rng)).collect(); + let bases1 = bases.clone(); + let add: Vec<_> = bases.into_iter().zip(bases2.iter()) + .map(|(p1, p2)| p1 + p2) + .collect(); + assert_eq!(add, batch_add_affine(bases1.clone(), bases2.clone())); + + let _timer = start_timer!(|| format!("Batch affine folding, log(n) = {log_n}")); + let x_bases2 = batch_mul_by_x_affine(bases2.clone(), x); + let res = batch_add_affine(bases1.clone(), x_bases2); + end_timer!(_timer); + + let _timer = start_timer!(|| format!("Naive folding, log(n) = {log_n}")); + let res_: Vec = ark_std::cfg_into_iter!(bases1).zip(ark_std::cfg_into_iter!(bases2)) + .map(|(l, r)| l + r * x) + .collect(); + let _to_affine = start_timer!(|| "batch affine conversion"); + let res_ = ark_pallas::Projective::normalize_batch(&res_); + end_timer!(_to_affine); + end_timer!(_timer); + + assert_eq!(res_, res); + } } From 2ffde5a1b3c4f277394a4088d5c1ab5f2d0c28e4 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Thu, 16 Apr 2026 17:31:24 +0300 Subject: [PATCH 11/36] fmt --- pasta-tree/src/lib.rs | 176 +++++++++++++++++++++++---------- w3f-plonk-common/src/prover.rs | 3 +- w3f-ring-proof/src/lib.rs | 7 +- w3f-ring-proof/src/piop/mod.rs | 4 +- 4 files changed, 133 insertions(+), 57 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 60dd3a5..c2ee81e 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -4,11 +4,10 @@ pub fn add(left: u64, right: u64) -> u64 { #[cfg(test)] mod tests { + use ark_ec::AdditiveGroup; use ark_ec::scalar_mul::glv::GLVConfig; - use w3f_pcs::pcs::PcsParams; use ark_ec::scalar_mul::wnaf::WnafContext; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; - use ark_ec::AdditiveGroup; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; use ark_ff::{BigInteger, Field, Zero}; @@ -17,13 +16,14 @@ mod tests { use ark_poly::Polynomial; use ark_std::iterable::Iterable; use ark_std::rand::Rng; - use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; + use ark_std::{UniformRand, cfg_iter_mut, end_timer, start_timer, test_rng}; use ark_vesta::VestaConfig; use std::collections::BTreeSet; use w3f_pcs::aggregation::multiple::Transcript; + use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::ipa::IPA; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; - use w3f_pcs::pcs::{RawVerifierKey, PCS}; + use w3f_pcs::pcs::{PCS, RawVerifierKey}; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::PlonkProver; @@ -31,7 +31,7 @@ mod tests { use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ring_prover::RingProver; use w3f_ring_proof::ring_verifier::RingVerifier; - use w3f_ring_proof::{index, test_setup, ArkTranscript}; + use w3f_ring_proof::{ArkTranscript, index, test_setup}; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -47,7 +47,8 @@ mod tests { // setup let domain_size = 2usize.pow(9); - let (pcs_params, piop_params) = test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); + let (pcs_params, piop_params) = + test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); let keyset_size = piop_params.keyset_part_size; let pks = random_vec::(keyset_size, rng); let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); @@ -58,7 +59,9 @@ mod tests { // prover let fs = ArkTranscript::new(b"pasta-ring-proof-test"); let prover = RingProver::init(prover_key, piop_params.clone(), 0, fs.clone()); - let t_prove = start_timer!(|| format!("Proving IPA ring-proof with plonk, domain_size={domain_size}, keyset_size={keyset_size}")); + let t_prove = start_timer!(|| format!( + "Proving IPA ring-proof with plonk, domain_size={domain_size}, keyset_size={keyset_size}" + )); let (blinded_pk_, proof) = prover.rerandomize_pk(pk_idx, blinding); end_timer!(t_prove); assert_eq!(blinded_pk_, blinded_pk); @@ -91,7 +94,8 @@ mod tests { // setup let domain_size = 2usize.pow(9); - let (pcs_params, piop_params) = test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); + let (pcs_params, piop_params) = + test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); let keyset_size = piop_params.keyset_part_size; let pks = random_vec::(keyset_size, rng); let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); @@ -106,16 +110,36 @@ mod tests { let pcs_vk = verifier_key.pcs_raw_vk.prepare(); // prover - let piop = PiopProver::::build(&piop_params, prover_key.fixed_columns.clone(), pk_idx, blinding); - let t_prove = start_timer!(|| format!("Proving IPA ring-proof with shplonk, domain_size={domain_size}, keyset_size={keyset_size}")); + let piop = PiopProver::::build( + &piop_params, + prover_key.fixed_columns.clone(), + pk_idx, + blinding, + ); + let t_prove = start_timer!(|| format!( + "Proving IPA ring-proof with shplonk, domain_size={domain_size}, keyset_size={keyset_size}" + )); let zeta = ark_pallas::Fr::rand(rng); let columns = as ProverPiop>::columns(&piop); let (quotient, agg_lin) = { - let constraints = as ProverPiop>::constraints(&piop); - let alphas: Vec<_> = (0..constraints.len()).map(|_| ark_pallas::Fr::rand(rng)).collect(); - let agg_constraint_poly = PlonkProver::::aggregate_evaluations(&constraints, &alphas).interpolate(); - let quotient = piop_params.domain.divide_by_vanishing_poly(&agg_constraint_poly); - let constraints_lin = as ProverPiop>::constraints_lin(&piop, &zeta); + let constraints = + as ProverPiop>::constraints(&piop); + let alphas: Vec<_> = (0..constraints.len()) + .map(|_| ark_pallas::Fr::rand(rng)) + .collect(); + let agg_constraint_poly = + PlonkProver::::aggregate_evaluations( + &constraints, + &alphas, + ) + .interpolate(); + let quotient = piop_params + .domain + .divide_by_vanishing_poly(&agg_constraint_poly); + let constraints_lin = + as ProverPiop>::constraints_lin( + &piop, &zeta, + ); let agg_lin = w3f_pcs::aggregation::single::aggregate_polys(&constraints_lin, &alphas); (quotient, agg_lin) }; @@ -128,19 +152,38 @@ mod tests { // commitments let mut poly_cs = verifier_key.fixed_columns_committed.as_vec(); - let t_commit = start_timer!(|| format!("Commiting to {} columns of degree = {} and the quotient of degree = {}", polys.len()-5, polys[3].degree(), polys[7].degree())); + let t_commit = start_timer!(|| format!( + "Commiting to {} columns of degree = {} and the quotient of degree = {}", + polys.len() - 5, + polys[3].degree(), + polys[7].degree() + )); // skip the instance columns and the linearirization polynomial `agg_lin` - poly_cs.extend(polys[3..polys.len() - 1].iter().map(|p| PallasIPA::commit(&pcs_ck, p).unwrap())); + poly_cs.extend( + polys[3..polys.len() - 1] + .iter() + .map(|p| PallasIPA::commit(&pcs_ck, p).unwrap()), + ); end_timer!(t_commit); poly_cs.push(PallasIPA::commit(&pcs_ck, &agg_lin).unwrap()); - let coord_sets: Vec> = coord_vecs.iter().cloned().map(BTreeSet::from_iter).collect(); - let vals: Vec<_> = polys.iter().zip(coord_vecs.iter()) + let coord_sets: Vec> = coord_vecs + .iter() + .cloned() + .map(BTreeSet::from_iter) + .collect(); + let vals: Vec<_> = polys + .iter() + .zip(coord_vecs.iter()) .map(|(f, xs)| xs.iter().map(|x| f.evaluate(&x)).collect::>()) .collect(); let transcript = &mut Coeffs(ark_pallas::Fr::rand(rng), ark_pallas::Fr::rand(rng)); - let t_open = start_timer!(|| format!("Opening IPA ring-proof with shplonk, {} polys, max_degree = {}", polys.len(), polys[7].degree())); + let t_open = start_timer!(|| format!( + "Opening IPA ring-proof with shplonk, {} polys, max_degree = {}", + polys.len(), + polys[7].degree() + )); let proof = Shplonk::::open_many( &pcs_ck, &polys, @@ -167,8 +210,13 @@ mod tests { fn _bench_msm(log_n: u32) { let rng = &mut test_rng(); let n = 2usize.pow(log_n); - let (scalars, bases): (Vec<_>, Vec<_>) = (0..n).map(|_| (C::ScalarField::rand(rng), C::Affine::rand(rng))).unzip(); - let t_msm = start_timer!(|| format!("log(n)={log_n}, MSM on {}", ark_std::any::type_name::())); + let (scalars, bases): (Vec<_>, Vec<_>) = (0..n) + .map(|_| (C::ScalarField::rand(rng), C::Affine::rand(rng))) + .unzip(); + let t_msm = start_timer!(|| format!( + "log(n)={log_n}, MSM on {}", + ark_std::any::type_name::() + )); let _res = C::msm(&bases, &scalars); end_timer!(t_msm); } @@ -205,7 +253,11 @@ mod tests { end_timer!(t_ipa_commit); } - fn mul_endo_wnaf(p: ark_pallas::Projective, k1: (bool, ark_pallas::Fr), k2: (bool, ark_pallas::Fr)) -> ark_pallas::Projective { + fn mul_endo_wnaf( + p: ark_pallas::Projective, + k1: (bool, ark_pallas::Fr), + k2: (bool, ark_pallas::Fr), + ) -> ark_pallas::Projective { let mut p1 = p; let mut p2 = PallasConfig::endomorphism(&p); if !k1.0 { @@ -251,24 +303,30 @@ mod tests { fn _bench_folding(log_n: u32) { let rng = &mut test_rng(); let n = 2usize.pow(log_n); - let (l, r): (Vec, Vec) = (0..n).map(|_| (ark_pallas::Affine::rand(rng), ark_pallas::Affine::rand(rng))).unzip(); + let (l, r): (Vec, Vec) = (0..n) + .map(|_| (ark_pallas::Affine::rand(rng), ark_pallas::Affine::rand(rng))) + .unzip(); let x = ark_pallas::Fr::rand(rng); let _timer = start_timer!(|| format!("Naive folding, log(n) = {log_n}")); - let res: Vec = ark_std::cfg_iter!(l).zip(r.clone()) + let res: Vec = ark_std::cfg_iter!(l) + .zip(r.clone()) .map(|(l, r)| r * x + l) .collect(); end_timer!(_timer); let _timer = start_timer!(|| format!("Naive folding with endo, log(n) = {log_n}")); - let res_: Vec = ark_std::cfg_into_iter!(l.clone()).zip(ark_std::cfg_into_iter!(r.clone())) + let res_: Vec = ark_std::cfg_into_iter!(l.clone()) + .zip(ark_std::cfg_into_iter!(r.clone())) .map(|(l, r)| l + ::glv_mul_affine(r, x)) .collect(); end_timer!(_timer); assert_eq!(res_, res); - let _timer = start_timer!(|| format!("Naive folding with endo and w-NAF, log(n) = {log_n}")); + let _timer = + start_timer!(|| format!("Naive folding with endo and w-NAF, log(n) = {log_n}")); let ((sgn_k1, k1), (sgn_k2, k2)) = PallasConfig::scalar_decomposition(x); - let res_: Vec = ark_std::cfg_into_iter!(l).zip(ark_std::cfg_iter!(r)) + let res_: Vec = ark_std::cfg_into_iter!(l) + .zip(ark_std::cfg_iter!(r)) .map(|(l, r)| l + mul_endo_wnaf(r.into_group(), (sgn_k1, k1), (sgn_k2, k2))) .collect(); end_timer!(_timer); @@ -276,32 +334,33 @@ mod tests { } fn batch_double_affine(bases: Vec>) -> Vec> { - let mut denoms: Vec = ark_std::cfg_iter!(bases) - .map(|p| p.y + p.y) - .collect(); + let mut denoms: Vec = ark_std::cfg_iter!(bases).map(|p| p.y + p.y).collect(); ark_ff::batch_inversion(&mut denoms); - ark_std::cfg_iter!(bases).zip(denoms).map(|(p, _2y_inv)| { - let (x, y) = p.xy().unwrap(); - let t = _2y_inv * (x.square() * C::BaseField::from(3) + ::COEFF_A); // (3x^2 + a) / 2y - let x_n = t.square() - x - x; - let y_n = t * (x - x_n) - y; - Affine::::new_unchecked(x_n, y_n) - }).collect() + ark_std::cfg_iter!(bases) + .zip(denoms) + .map(|(p, _2y_inv)| { + let (x, y) = p.xy().unwrap(); + let t = + _2y_inv * (x.square() * C::BaseField::from(3) + ::COEFF_A); // (3x^2 + a) / 2y + let x_n = t.square() - x - x; + let y_n = t * (x - x_n) - y; + Affine::::new_unchecked(x_n, y_n) + }) + .collect() } fn batch_double_affine_in_place(bases: &mut [Affine]) { let three = C::BaseField::from(3); let sw_a = ::COEFF_A; - let mut denoms: Vec = ark_std::cfg_iter!(bases) - .map(|p| p.y + p.y) - .collect(); + let mut denoms: Vec = ark_std::cfg_iter!(bases).map(|p| p.y + p.y).collect(); ark_ff::batch_inversion(&mut denoms); // ark_ff::batch_inversion_and_mul(&mut denoms, &C::BaseField::one()); - cfg_iter_mut!(bases).zip(ark_std::cfg_into_iter!(denoms)) + cfg_iter_mut!(bases) + .zip(ark_std::cfg_into_iter!(denoms)) .for_each(|(p, _2y_inv)| { let t = _2y_inv * (p.x.square() * three + sw_a); // (3x^2 + a) / 2y let old_x = p.x; @@ -310,7 +369,10 @@ mod tests { }) } - fn batch_add_affine(bases1: Vec>, bases2: Vec>) -> Vec> { + fn batch_add_affine( + bases1: Vec>, + bases2: Vec>, + ) -> Vec> { let mut denoms: Vec = ark_std::cfg_iter!(bases1) .zip(ark_std::cfg_iter!(bases2)) .map(|(p1, p2)| p2.x - p1.x) @@ -328,10 +390,14 @@ mod tests { let x_n = t.square() - x1 - x2; let y_n = t * (x1 - x_n) - y1; Affine::::new_unchecked(x_n, y_n) - }).collect() + }) + .collect() } - fn batch_mul_by_x_affine(bases: Vec>, x: C::ScalarField) -> Vec> { + fn batch_mul_by_x_affine( + bases: Vec>, + x: C::ScalarField, + ) -> Vec> { let mut res: Vec> = bases.clone(); for b in ark_ff::BitIteratorBE::without_leading_zeros(x.into_bigint()).skip(1) { batch_double_affine_in_place(&mut res); @@ -351,16 +417,21 @@ mod tests { let n = 2usize.pow(log_n); let bases: Vec<_> = (0..n).map(|_| ark_pallas::Affine::rand(rng)).collect(); let x = ark_pallas::Fr::rand(rng); - let dbl: Vec<_> = bases.iter().map(|p| { - let mut p = p.into_group(); - p.double_in_place(); - p.into_affine() - }).collect(); + let dbl: Vec<_> = bases + .iter() + .map(|p| { + let mut p = p.into_group(); + p.double_in_place(); + p.into_affine() + }) + .collect(); assert_eq!(dbl, batch_double_affine(bases.clone())); let bases2: Vec<_> = (0..n).map(|_| ark_pallas::Affine::rand(rng)).collect(); let bases1 = bases.clone(); - let add: Vec<_> = bases.into_iter().zip(bases2.iter()) + let add: Vec<_> = bases + .into_iter() + .zip(bases2.iter()) .map(|(p1, p2)| p1 + p2) .collect(); assert_eq!(add, batch_add_affine(bases1.clone(), bases2.clone())); @@ -371,7 +442,8 @@ mod tests { end_timer!(_timer); let _timer = start_timer!(|| format!("Naive folding, log(n) = {log_n}")); - let res_: Vec = ark_std::cfg_into_iter!(bases1).zip(ark_std::cfg_into_iter!(bases2)) + let res_: Vec = ark_std::cfg_into_iter!(bases1) + .zip(ark_std::cfg_into_iter!(bases2)) .map(|(l, r)| l + r * x) .collect(); let _to_affine = start_timer!(|| "batch affine conversion"); diff --git a/w3f-plonk-common/src/prover.rs b/w3f-plonk-common/src/prover.rs index c221191..b446e2d 100644 --- a/w3f-plonk-common/src/prover.rs +++ b/w3f-plonk-common/src/prover.rs @@ -58,7 +58,8 @@ impl, T: PlonkTranscript> PlonkProver let agg_constraint_poly = agg_constraint_poly.interpolate(); let quotient_poly = piop.domain().divide_by_vanishing_poly(&agg_constraint_poly); // The prover commits to the quotient polynomial... - let _t_commit_q = start_timer!(|| format!("Committing to deg(f)={}", quotient_poly.degree())); + let _t_commit_q = + start_timer!(|| format!("Committing to deg(f)={}", quotient_poly.degree())); let quotient_commitment = CS::commit(&self.pcs_ck, "ient_poly).unwrap(); end_timer!(_t_commit_q); transcript.add_quotient_commitment("ient_commitment); diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 7290a5c..8a16a80 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -51,7 +51,10 @@ impl ArkTranscript { } } -pub fn test_setup, G: SWCurveConfig>(rng: &mut R, domain_size: usize) -> (CS::Params, PiopParams) { +pub fn test_setup, G: SWCurveConfig>( + rng: &mut R, + domain_size: usize, +) -> (CS::Params, PiopParams) { let setup_degree = 3 * domain_size; let pcs_params = CS::setup(setup_degree, rng); let domain = Domain::new(domain_size, true); @@ -66,7 +69,7 @@ pub fn test_setup, G: SWCurveConfig> FixedColumnsCommitted { } } -impl> FixedColumnsCommitted> { - pub fn from_ring, G: SWCurveConfig>( +impl> FixedColumnsCommitted> { + pub fn from_ring, G: SWCurveConfig>( ring: &Ring, ) -> Self { let cx = WrappedAffine(ring.cx); From e6151865d4464cbc2559226cd837c3ee830d26da Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Tue, 21 Apr 2026 17:24:08 +0300 Subject: [PATCH 12/36] hiding ipa pcs --- pasta-tree/src/ipa_hiding.rs | 113 +++++++++++++++++++++++++++++++++++ pasta-tree/src/lib.rs | 2 + 2 files changed, 115 insertions(+) create mode 100644 pasta-tree/src/ipa_hiding.rs diff --git a/pasta-tree/src/ipa_hiding.rs b/pasta-tree/src/ipa_hiding.rs new file mode 100644 index 0000000..75ba659 --- /dev/null +++ b/pasta-tree/src/ipa_hiding.rs @@ -0,0 +1,113 @@ +use ark_ec::CurveGroup; +use ark_ff::PrimeField; +use ark_poly::{DenseUVPolynomial, Polynomial}; +use ark_std::rand::Rng; +use ark_std::UniformRand; +use w3f_pcs::pcs::ipa::ipa_pc; +use w3f_pcs::pcs::ipa; +use w3f_pcs::pcs::kzg::commitment::WrappedAffine; +use w3f_pcs::pcs::PCS; +use w3f_pcs::Poly; + +// To open a hiding commitment `Cp = Commit(p, t1) = (p0.G0 + ... + pn.Gn) + t1.H` at `z`, +// the prover: +// 1. Computes a hiding commitment to a random `q` such that `deg(q) = deg(p)` and `q(z) = 0` +// `Cq = Commit(q, t2) = (q0.G0 + ... + qn.Gn) + t2.H`. +// 2. Computes the blinded polynomial `p' = p + a.q`, p'(z) = p(z) + a.q(z) = p(z)`. +// 3. Opens the non-hiding commitment `Cp' = Commit(p', 0)` to the blinded polynomial `p'`. +// 4. Reveals `Cq` and `t = t1 + a.t2` to the verifier. +// The verifier +// 1. Computes the non-hiding commitment `Cp'` as `Cp + a.Cq - t'H = (Cp - t1.H) + a.(Cq - t2.H)`. +// 2. Verifies the opening against `Cp'`. +pub struct HidingIpa { + ipa_pcs: ipa::IPA, + h: C::Affine, +} + +/// `Cp = Commit(p, t1) = (p0.G0 + ... + pn.Gn) + t1.H`. +pub struct HidingProof { + /// A hiding commitment to the blinding polynomial `q`, `deg(q) = deg(p), q(z) = 0`. + /// `Commit(q, t2) = (q0.G0 + ... + qn.Gn) + t2.H`. + q: C::Affine, + /// The blinding factor `t` in the hiding commitment `Cp' = Cp + a.Cq` to the blinded polynomial `p' = p + a.q`. + /// `t = t1 + a.t2`, `Cp' = Commit(p', t) = Commit(p', 0) + (t1 + a.t2).H` + t: C::ScalarField, + /// Opening proof for the non-hiding commitment `Commit(p', 0)` to `p'`. + ipa_pcs_proof: ipa_pc::Proof, + // TODO: remove + a: C::ScalarField, +} + +impl> HidingIpa { + fn setup(max_degree: usize, rng: &mut R) -> Self { + let ipa_pcs = ipa::IPA::setup(max_degree, rng); + let h = C::Affine::rand(rng); + Self { + ipa_pcs, + h, + } + } + + fn commit(&self, p: &Poly, t: F) -> Result, ()> { + let c = ipa::IPA::commit(&self.ipa_pcs, p)?; + let c = c.0 + self.h * t; + let c = c.into_affine(); + Ok(WrappedAffine(c)) + } + + fn open(&self, p: &Poly, z: F, t: F, rng: &mut R) -> Result, ()> { + let t1 = t; + let mut q = Poly::rand(p.degree(), rng); + let q_at_z = q.evaluate(&z); + q[0] -= q_at_z; + debug_assert!(q.evaluate(&z).is_zero()); + let t2 = F::rand(rng); + let cq = self.commit(&q, t2)?.0; + let a = F::rand(rng); // TODO: that's a FS point + let p = p + q * a; + let t = t1 + t2 * a; + let ipa_pcs_proof = ipa::IPA::open(&self.ipa_pcs, &p, z)?; + Ok(HidingProof{ + q: cq, + t, + ipa_pcs_proof, + a + }) + } + + fn verify(&self, p: C::Affine, z: F, v: F, proof: HidingProof) -> Result<(), ()> { + let p = p + proof.q * proof.a - self.h * proof.t; + ipa::IPA::verify(&self.ipa_pcs, WrappedAffine(p.into_affine()), z, v, proof.ipa_pcs_proof) + } +} + + +#[cfg(test)] +mod tests { + use ark_ff::Zero; + use ark_poly::{DenseUVPolynomial, Polynomial}; + use ark_std::{test_rng, UniformRand}; + use w3f_pcs::Poly; + use crate::ipa_hiding::HidingIpa; + + #[test] + fn test_hiding_ipa_opening() { + let rng = &mut test_rng(); + + let max_coeffs = 2usize.pow(6); + let max_degree = max_coeffs - 1; + + let hiding_pcs = HidingIpa::::setup(max_coeffs - 1, rng); + + let p = Poly::rand(max_degree, rng); + let t = ark_pallas::Fr::rand(rng); + + let c = hiding_pcs.commit(&p, t).unwrap().0; + + let z = ark_pallas::Fr::rand(rng); + let v = p.evaluate(&z); + let pi = hiding_pcs.open(&p, z, t, rng).unwrap(); + + assert!(hiding_pcs.verify(c, z, v, pi).is_ok()); + } +} \ No newline at end of file diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index c2ee81e..ef50a9b 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,3 +1,5 @@ +mod ipa_hiding; + pub fn add(left: u64, right: u64) -> u64 { left + right } From 1edc7fbf6fa8fc12d9073669f6abb1abfb11b9bf Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 15 May 2026 06:27:45 +0300 Subject: [PATCH 13/36] workspace toml updated --- Cargo.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a8de4c5..8969e70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ -[workspace] +[workspaceworkspace] resolver = "2" members = [ - # "evm-vrfier", +# "evm-vrfier", + "pasta-tree", "w3f-plonk-common", "w3f-ring-proof", # "w3f-ring-vrf-snark", @@ -13,7 +14,8 @@ ark-ff = { version = "0.5", default-features = false } ark-ec = { version = "0.5", default-features = false } ark-poly = { version = "0.5", default-features = false } ark-serialize = { version = "0.5", default-features = false, features = ["derive"] } -w3f-pcs = { version = "0.0.5", default-features = false } +#w3f-pcs = { version = "0.0.5", default-features = false } +w3f-pcs = { path = "../fflonk", 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 } From 65a8efa6f750149274503c251fa3379b004fe93a Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 15 May 2026 06:47:04 +0300 Subject: [PATCH 14/36] workspace toml fixed --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8969e70..a2acc82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -[workspaceworkspace] +[workspace] resolver = "2" members = [ # "evm-vrfier", From e09d5675d49afaabedb871b4e5ebce0337eb28f8 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 15 May 2026 06:47:19 +0300 Subject: [PATCH 15/36] hiding ipa cleaned up --- pasta-tree/src/ipa_hiding.rs | 105 +++++++++++++++++++++++++++-------- pasta-tree/src/lib.rs | 3 +- 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/pasta-tree/src/ipa_hiding.rs b/pasta-tree/src/ipa_hiding.rs index 75ba659..6358277 100644 --- a/pasta-tree/src/ipa_hiding.rs +++ b/pasta-tree/src/ipa_hiding.rs @@ -1,10 +1,11 @@ use ark_ec::CurveGroup; -use ark_ff::PrimeField; +use ark_ff::{PrimeField, Zero}; use ark_poly::{DenseUVPolynomial, Polynomial}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::rand::Rng; use ark_std::UniformRand; use w3f_pcs::pcs::ipa::ipa_pc; -use w3f_pcs::pcs::ipa; +use w3f_pcs::pcs::{ipa, CommitterKey, PcsParams, RawVerifierKey, VerifierKey}; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; use w3f_pcs::pcs::PCS; use w3f_pcs::Poly; @@ -19,12 +20,14 @@ use w3f_pcs::Poly; // The verifier // 1. Computes the non-hiding commitment `Cp'` as `Cp + a.Cq - t'H = (Cp - t1.H) + a.(Cq - t2.H)`. // 2. Verifies the opening against `Cp'`. +#[derive(Clone, Debug, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct HidingIpa { - ipa_pcs: ipa::IPA, - h: C::Affine, + pub ipa_pcs: ipa::IPA, + pub h: C::Affine, } /// `Cp = Commit(p, t1) = (p0.G0 + ... + pn.Gn) + t1.H`. +#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)] pub struct HidingProof { /// A hiding commitment to the blinding polynomial `q`, `deg(q) = deg(p), q(z) = 0`. /// `Commit(q, t2) = (q0.G0 + ... + qn.Gn) + t2.H`. @@ -39,7 +42,60 @@ pub struct HidingProof { } impl> HidingIpa { - fn setup(max_degree: usize, rng: &mut R) -> Self { + pub fn commit_hiding(&self, p: &Poly, t: F) -> Result, ()> { + let c = ipa::IPA::commit(&self.ipa_pcs, p)?; + self.reblind(c.0, F::zero(), t) + } + + pub fn reblind(&self, c: C::Affine, r_old: F, r_new: F) -> Result, ()> { + let c = c + self.h * (r_new - r_old); + let c = c.into_affine(); + Ok(WrappedAffine(c)) + } +} + +impl CommitterKey for HidingIpa { + fn max_degree(&self) -> usize { + self.ipa_pcs.g.len() - 1 + } +} + +impl VerifierKey for HidingIpa {} + +impl RawVerifierKey for HidingIpa { + type VK = Self; + + fn prepare(&self) -> Self::VK { + self.clone() + } +} + +impl PcsParams for HidingIpa { + type CK = Self; + type VK = Self; + type RVK = Self; + + fn ck(&self) -> Self::CK { + self.clone() + } + + fn vk(&self) -> Self::VK { + self.clone() + } + + fn raw_vk(&self) -> Self::RVK { + self.clone() + } +} + +impl PCS for HidingIpa { + type C = WrappedAffine; + type Proof = HidingProof; + type CK = Self; + type VK = Self; + type Params = Self; + + fn setup(max_degree: usize, rng: &mut R) -> Self::Params { let ipa_pcs = ipa::IPA::setup(max_degree, rng); let h = C::Affine::rand(rng); Self { @@ -48,45 +104,46 @@ impl> HidingIpa { } } - fn commit(&self, p: &Poly, t: F) -> Result, ()> { - let c = ipa::IPA::commit(&self.ipa_pcs, p)?; - let c = c.0 + self.h * t; - let c = c.into_affine(); - Ok(WrappedAffine(c)) + fn commit(ck: &Self::CK, p: &Poly) -> Result { + Self::commit_hiding(ck, p, C::ScalarField::zero()) + } + + fn open(_ck: &Self::CK, _p: &Poly, _x: C::ScalarField) -> Result { + todo!() } - fn open(&self, p: &Poly, z: F, t: F, rng: &mut R) -> Result, ()> { + fn open_hiding(ck: &Self::CK, p: &Poly, z: C::ScalarField, t: C::ScalarField, rng: &mut R) -> Result { let t1 = t; let mut q = Poly::rand(p.degree(), rng); let q_at_z = q.evaluate(&z); q[0] -= q_at_z; debug_assert!(q.evaluate(&z).is_zero()); - let t2 = F::rand(rng); - let cq = self.commit(&q, t2)?.0; - let a = F::rand(rng); // TODO: that's a FS point + let t2 = C::ScalarField::rand(rng); + let cq = ck.commit_hiding(&q, t2)?.0; + let a = C::ScalarField::rand(rng); // TODO: that's a FS point let p = p + q * a; let t = t1 + t2 * a; - let ipa_pcs_proof = ipa::IPA::open(&self.ipa_pcs, &p, z)?; - Ok(HidingProof{ + let ipa_pcs_proof = ipa::IPA::open(&ck.ipa_pcs, &p, z)?; + Ok(HidingProof { q: cq, t, ipa_pcs_proof, - a + a, }) } - fn verify(&self, p: C::Affine, z: F, v: F, proof: HidingProof) -> Result<(), ()> { - let p = p + proof.q * proof.a - self.h * proof.t; - ipa::IPA::verify(&self.ipa_pcs, WrappedAffine(p.into_affine()), z, v, proof.ipa_pcs_proof) + fn verify(vk: &Self::VK, c: Self::C, x: C::ScalarField, z: C::ScalarField, proof: Self::Proof) -> Result<(), ()> { + let c = c.0 + proof.q * proof.a - vk.h * proof.t; + ipa::IPA::verify(&vk.ipa_pcs, WrappedAffine(c.into_affine()), x, z, proof.ipa_pcs_proof) } } #[cfg(test)] mod tests { - use ark_ff::Zero; use ark_poly::{DenseUVPolynomial, Polynomial}; use ark_std::{test_rng, UniformRand}; + use w3f_pcs::pcs::PCS; use w3f_pcs::Poly; use crate::ipa_hiding::HidingIpa; @@ -102,12 +159,12 @@ mod tests { let p = Poly::rand(max_degree, rng); let t = ark_pallas::Fr::rand(rng); - let c = hiding_pcs.commit(&p, t).unwrap().0; + let c = hiding_pcs.commit_hiding(&p, t).unwrap(); let z = ark_pallas::Fr::rand(rng); let v = p.evaluate(&z); - let pi = hiding_pcs.open(&p, z, t, rng).unwrap(); + let pi = HidingIpa::::open_hiding(&hiding_pcs, &p, z, t, rng).unwrap(); - assert!(hiding_pcs.verify(c, z, v, pi).is_ok()); + assert!(HidingIpa::::verify(&hiding_pcs, c, z, v, pi).is_ok()); } } \ No newline at end of file diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index ef50a9b..f438710 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,4 +1,4 @@ -mod ipa_hiding; +pub mod ipa_hiding; pub fn add(left: u64, right: u64) -> u64 { left + right @@ -190,6 +190,7 @@ mod tests { &pcs_ck, &polys, &coord_sets, + ark_pallas::Fr::zero(), transcript, ); end_timer!(t_open); From 93164081be1a44df549fcb5864b3dfbaeaf50624 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 15 May 2026 07:21:50 +0300 Subject: [PATCH 16/36] verkle path struct --- pasta-tree/src/lib.rs | 179 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 170 insertions(+), 9 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index f438710..de2d71b 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,15 +1,136 @@ +#![feature(bool_to_result)] +use crate::ipa_hiding::HidingIpa; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_ff::PrimeField; +use ark_poly::{EvaluationDomain, Evaluations, Radix2EvaluationDomain}; +use ark_std::rand::Rng; +use w3f_pcs::pcs::PCS; + pub mod ipa_hiding; -pub fn add(left: u64, right: u64) -> u64 { - left + right +pub struct CycleSideParams { + ipa_pcs: HidingIpa, + domain: Radix2EvaluationDomain, + extra_elements: Vec, + extra_commitment: C, +} + +pub struct CycleParams { + c0_params: CycleSideParams, + c1_params: CycleSideParams, +} + +impl CycleSideParams { + fn setup(log_n: u32, rng: &mut R) -> Result { + let n = 2usize.pow(log_n); + let domain = Radix2EvaluationDomain::new(n).ok_or(())?; + let ipa_pcs = HidingIpa::setup(n - 1, rng); + Ok(Self { + ipa_pcs, + domain, + extra_elements: vec![], + extra_commitment: C::zero(), + }) + } + + fn commit_node(&self, children_x_coords: Vec, blinding: C::ScalarField) -> Result { + (children_x_coords.len() <= self.domain.size() - self.extra_elements.len()).ok_or(())?; + let evals = Evaluations::from_vec_and_domain(children_x_coords, self.domain); + let poly = evals.interpolate_by_ref(); + let x_coords_committed = self.ipa_pcs.commit_hiding(&poly, blinding)?.0; + let node_committed = x_coords_committed + self.extra_commitment; + Ok(node_committed) + } +} + +impl CycleParams { + fn setup(log_n: u32, rng: &mut R) -> Result { + let c0_params = CycleSideParams::setup(log_n, rng)?; + let c1_params = CycleSideParams::setup(log_n, rng)?; + Ok(Self { + c0_params, + c1_params, + }) + } +} + +#[derive(Clone)] +pub struct LevelWitness { + siblings: Vec, + i: usize, +} + +impl LevelWitness { + fn x_coords(&self) -> Vec { + self.siblings.iter() + .map(|p| p.x()) + .flatten() + .collect() + } + + fn path_node(&self) -> G { + self.siblings[self.i] + } + + fn commit_node>(&self, params: &CycleSideParams, blinding: C::ScalarField) -> Result + where + G::BaseField: PrimeField, + { + params.commit_node(self.x_coords(), blinding) + } +} + +/// Leaves are points on `C0` +struct MembershipWitness { + path_0: Vec>, + path_1: Vec>, +} + +enum CycleCurve { + C0(C0), + C1(C1), +} + +impl MembershipWitness +where + F0: PrimeField, + F1: PrimeField, + C0: CurveGroup, + C1: CurveGroup, +{ + fn validate(&self, params: &CycleParams) -> Result<(C0::Affine, CycleCurve), ()> { + let mut path_0_iter = self.path_0.iter(); + let leaf_node = path_0_iter.next().unwrap(); + let leaf = leaf_node.path_node(); + + let node_0 = leaf_node; + let mut parent_on_c1 = node_0.commit_node(¶ms.c1_params, C1::ScalarField::zero()).unwrap().into_affine(); + let mut root = CycleCurve::C1(parent_on_c1); + for node_1 in self.path_1.iter() { + assert_eq!(parent_on_c1, node_1.path_node()); + let parent_on_c0 = node_1.commit_node(¶ms.c0_params, C0::ScalarField::zero()).unwrap().into_affine(); + root = CycleCurve::C0(parent_on_c0); + match path_0_iter.next() { + Some(node_0) => { + assert_eq!(parent_on_c0, node_0.path_node()); + parent_on_c1 = node_0.commit_node(¶ms.c1_params, C1::ScalarField::zero()).unwrap().into_affine(); + root = CycleCurve::C1(parent_on_c1); + }, + None => break + } + } + Ok((leaf, root)) + } } #[cfg(test)] mod tests { - use ark_ec::AdditiveGroup; + use super::*; + use crate::CycleParams; use ark_ec::scalar_mul::glv::GLVConfig; use ark_ec::scalar_mul::wnaf::WnafContext; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; + use ark_ec::AdditiveGroup; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; use ark_ff::{BigInteger, Field, Zero}; @@ -18,30 +139,70 @@ mod tests { use ark_poly::Polynomial; use ark_std::iterable::Iterable; use ark_std::rand::Rng; - use ark_std::{UniformRand, cfg_iter_mut, end_timer, start_timer, test_rng}; + use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; use std::collections::BTreeSet; use w3f_pcs::aggregation::multiple::Transcript; - use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::ipa::IPA; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; - use w3f_pcs::pcs::{PCS, RawVerifierKey}; + use w3f_pcs::pcs::PcsParams; + use w3f_pcs::pcs::{RawVerifierKey, PCS}; use w3f_pcs::shplonk::Shplonk; + use w3f_pcs::Poly; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::PlonkProver; use w3f_plonk_common::test_helpers::random_vec; use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ring_prover::RingProver; use w3f_ring_proof::ring_verifier::RingVerifier; - use w3f_ring_proof::{ArkTranscript, index, test_setup}; + use w3f_ring_proof::{index, test_setup, ArkTranscript}; #[cfg(feature = "parallel")] use rayon::prelude::*; - use w3f_pcs::Poly; + type PallasIPA = IPA; type PallasC = WrappedAffine; + + #[test] + fn test_membership_witness() { + let rng = &mut test_rng(); + + let params = CycleParams::::setup(9, rng).unwrap(); + + let c0_capacity = params.c0_params.domain.size(); + let leaves = random_vec::(c0_capacity, rng); + let leaf_index = rng.gen_range(0..c0_capacity); + let node_0 = LevelWitness { + siblings: leaves, + i: leaf_index, + }; + let parent = node_0.commit_node(¶ms.c1_params, ark_vesta::Fr::zero()).unwrap().into_affine(); + + let c1_capacity = params.c1_params.domain.size(); + let parent_index = rng.gen_range(0..c1_capacity); + let mut inner_nodes = random_vec::(c1_capacity, rng); + inner_nodes[parent_index] = parent; + let node_1 = LevelWitness { + siblings: inner_nodes, + i: parent_index, + }; + let root = node_1.commit_node(¶ms.c0_params, ark_pallas::Fr::zero()).unwrap().into_affine(); + + let path = MembershipWitness { + path_0: vec![node_0.clone()], + path_1: vec![node_1.clone()], + }; + + let (leaf, root_) = path.validate(¶ms).unwrap(); + assert_eq!(leaf, node_0.path_node()); + match root_ { + CycleCurve::C0(c0) => assert_eq!(c0, root), + _ => panic!() + } + } + // cargo test test_pasta_ring_plonk --release --features="print-trace" -- --show-output #[test] fn test_pasta_ring_plonk() { @@ -134,7 +295,7 @@ mod tests { &constraints, &alphas, ) - .interpolate(); + .interpolate(); let quotient = piop_params .domain .divide_by_vanishing_poly(&agg_constraint_poly); From 438c0659b7df6310cadfde3c9e14af8625470abc Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 15 May 2026 07:35:30 +0300 Subject: [PATCH 17/36] per level proofs added --- pasta-tree/src/level/mod.rs | 176 +++++++++++++++++++++++++++++++ pasta-tree/src/level/prover.rs | 82 ++++++++++++++ pasta-tree/src/level/verifier.rs | 73 +++++++++++++ pasta-tree/src/lib.rs | 31 +++--- 4 files changed, 347 insertions(+), 15 deletions(-) create mode 100644 pasta-tree/src/level/mod.rs create mode 100644 pasta-tree/src/level/prover.rs create mode 100644 pasta-tree/src/level/verifier.rs diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs new file mode 100644 index 0000000..64c0a4f --- /dev/null +++ b/pasta-tree/src/level/mod.rs @@ -0,0 +1,176 @@ +mod prover; +mod verifier; + +use crate::ipa_hiding::HidingIpa; +use crate::Coeffs; +use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; +use ark_ec::{CurveGroup, PrimeGroup}; +use ark_ff::{PrimeField, Zero}; +use ark_std::rand::Rng; +use ark_std::UniformRand; +use std::marker::PhantomData; +use w3f_pcs::pcs::{PcsParams, PCS}; +use w3f_pcs::shplonk::AggregateProof; +use w3f_plonk_common::domain::Domain; +use w3f_plonk_common::PiopProof; +use w3f_ring_proof::piop::{FixedColumns, RingCommitments, RingEvaluations}; +use w3f_ring_proof::{FixedColumnsCommitted, PiopParams, VerifierKey}; + +struct CycleSideParams> +{ + pcs_params: HidingIpa, + piop_params: PiopParams, +} + +struct CycleParams> +{ + c0_params: CycleSideParams, G>, + c1_params: CycleSideParams, C>, +} + +impl> CycleParams where C::BaseField: PrimeField { + pub fn setup(rng: &mut R, domain_size: usize) -> Self { + let setup_degree = 3 * domain_size; + let pcs_params_0 = HidingIpa::>::setup(setup_degree, rng); + let pcs_params_1 = HidingIpa::>::setup(setup_degree, rng); + let domain_0 = Domain::::new(domain_size, true); + let domain_1 = Domain::::new(domain_size, true); + let seed_0 = Affine::::rand(rng); + let padding_0 = Affine::::rand(rng); + let piop_params_0 = PiopParams::::setup(domain_0, pcs_params_1.h, seed_0, padding_0); + let seed_1 = Affine::::rand(rng); + let padding_1 = Affine::::rand(rng); + let piop_params_1 = PiopParams::::setup(domain_1, pcs_params_0.h, seed_1, padding_1); + Self { + c0_params: CycleSideParams { pcs_params: pcs_params_0, piop_params: piop_params_0 }, + c1_params: CycleSideParams { pcs_params: pcs_params_1, piop_params: piop_params_1 }, + } + } +} + +struct LevelProof { + piop_proof: PiopProof as PCS>::C, RingCommitments as PCS>::C>, RingEvaluations>, + pcs_opening_proof: AggregateProof>, + todo: Coeffs, +} + +type IPACommitment = as PCS<::ScalarField>>::C; + +impl> CycleSideParams { + pub fn setup(rng: &mut R, domain_size: usize) -> Self { + let setup_degree = 3 * domain_size; + let pcs_params = HidingIpa::::setup(setup_degree, rng); + let domain = Domain::new(domain_size, true); + let h = Affine::::rand(rng); + let seed = Affine::::rand(rng); + let padding = Affine::::rand(rng); + let piop_params = PiopParams::setup(domain, h, seed, padding); + Self { + pcs_params, + piop_params, + } + } + + pub fn commit_child_nodes(&self, nodes: &[Affine], r: C::ScalarField) -> ( + FixedColumns>, + VerifierKey> + ) { + let fixed_columns = self.piop_params.fixed_columns(&nodes); + let xs = fixed_columns.points.xs.as_poly(); + let ys = fixed_columns.points.ys.as_poly(); + let fixed_columns_committed = FixedColumnsCommitted { + points: [ + self.pcs_params.commit_hiding(xs, r).unwrap(), + self.pcs_params.commit_hiding(ys, C::ScalarField::zero()).unwrap(), + ], + ring_selector: self.pcs_params.commit_hiding(fixed_columns.ring_selector.as_poly(), C::ScalarField::zero()).unwrap(), + phantom: PhantomData, + }; + let verifier_key = VerifierKey { + pcs_raw_vk: self.pcs_params.raw_vk(), + fixed_columns_committed, + }; + (fixed_columns, verifier_key) + } +} + +#[cfg(test)] +mod tests { + use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; + use ark_ec::{AffineRepr, CurveGroup}; + use ark_ff::PrimeField; + use ark_ff::{Field, Zero}; + use ark_pallas::PallasConfig; + use ark_poly::DenseUVPolynomial; + use ark_std::rand::Rng; + use ark_std::{test_rng, UniformRand}; + use ark_vesta::VestaConfig; + use w3f_pcs::pcs::PCS; + use w3f_plonk_common::test_helpers::random_vec; + + use crate::level::{CycleParams, CycleSideParams}; + use crate::level::prover::LevelWitness; + + fn random_node, R: Rng>(params: &CycleSideParams, child: Option>, rng: &mut R) -> (C::Affine, LevelWitness) + { + let capacity = params.piop_params.keyset_part_size; + let mut children = random_vec::, _>(capacity, rng); + let i = rng.gen_range(0..capacity); + if child.is_some() { + children[i] = child.unwrap(); + } + let fixed_columns = params.piop_params.fixed_columns(&children); + let children_xs = fixed_columns.points.xs.as_poly(); + let parent = params.pcs_params.commit_hiding(children_xs, C::ScalarField::zero()); + let parent = parent.unwrap().0; + let witness = LevelWitness { + siblings: children, + i, + child_r: G::ScalarField::rand(rng), + parent_r: C::ScalarField::zero(), + }; + (parent, witness) + } + + fn _test_level_proof() + where + F0: PrimeField, + F1: PrimeField, + C0: SWCurveConfig, + C1: SWCurveConfig, + { + let rng = &mut test_rng(); + + // setup + let domain_size = 2usize.pow(9); + let CycleParams { + c0_params, + c1_params, + } = CycleParams::::setup(rng, domain_size); + + let (l1_node, mut l2_nodes) = random_node(&c1_params, None, rng); + let (l0_node, l1_nodes) = random_node(&c0_params, Some(l1_node), rng); + + let (_, l1_vk) = c0_params.commit_child_nodes(l1_nodes.siblings.as_slice(), F0::zero()); + + let root_fc = l1_vk.fixed_columns_committed; + let leaf = l2_nodes.siblings[l2_nodes.i]; + + let (l1_node_blinded, l1_proof) = c0_params.prove_level(&l1_nodes, rng); + assert!(c0_params.verify_level(root_fc, l1_node_blinded, l1_proof)); + + let l2_nodes_parent_r = l1_nodes.child_r; + let (l2_column, l2_vk) = c1_params.commit_child_nodes(l2_nodes.siblings.as_slice(), l2_nodes_parent_r); + let l1_node_fc = l2_vk.fixed_columns_committed; + assert_eq!(l1_node_fc.points[0].0, l1_node_blinded); + + l2_nodes.parent_r = l2_nodes_parent_r; + let (blinded_leaf, l2_proof) = c1_params.prove_level(&l2_nodes, rng); + assert!(c1_params.verify_level(l1_node_fc, blinded_leaf, l2_proof)); + } + + #[test] + fn test_level_proof() { + _test_level_proof::<_, _, PallasConfig, VestaConfig>() + } +} \ No newline at end of file diff --git a/pasta-tree/src/level/prover.rs b/pasta-tree/src/level/prover.rs new file mode 100644 index 0000000..dff2320 --- /dev/null +++ b/pasta-tree/src/level/prover.rs @@ -0,0 +1,82 @@ +use crate::ipa_hiding::HidingIpa; +use crate::level::{CycleSideParams, IPACommitment, LevelProof}; +use crate::Coeffs; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::CurveGroup; +use ark_std::rand::Rng; +use ark_std::{end_timer, start_timer, UniformRand}; +use std::collections::BTreeSet; +use w3f_pcs::pcs::PcsParams; +use w3f_pcs::shplonk::Shplonk; +use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; +use w3f_ring_proof::piop::prover::PiopProver; +use w3f_ring_proof::ArkTranscript; +use ark_poly::Polynomial; +use w3f_plonk_common::piop::ProverPiop; + +// Witness for the relation (C, C'; i, r, r', x1, ..., xn, yi | C = x1.G1 + ...+ xn.Gn + r'H, C' = (xi, yi) + r.H') +pub struct LevelWitness { + pub siblings: Vec>, + pub i: usize, + pub child_r: G::ScalarField, + pub parent_r: G::BaseField, + // TODO: precompute C +} + +impl> CycleSideParams { + // to prove a single level, the prover needs: + // 1. witness data: + // - parent randomizer + // - siblings + // - child index + // 2. level params + pub fn prove_level(&self, witness: &LevelWitness, rng: &mut R) -> (Affine, LevelProof) { + let (fixed_columns, verifier_key) = self.commit_child_nodes(&witness.siblings, witness.parent_r); + let piop = PiopProver::build(&self.piop_params, fixed_columns, witness.i, witness.child_r); + let blinded_pk = as ProverPiop>>::result(&piop); + // let blinded_parent = verifier_key.fixed_columns_committed.points[0].clone(); + let plonk_prover = PlonkProver::, _>::init(self.pcs_params.ck(), verifier_key, ArkTranscript::new(b"pasta-tree-level-proof")); + let (pcs_openings, piop_proof, mut transcript) = plonk_prover.reduce_to_pcs_opening(piop); + let PcsOpeningAt2Points { + polys_at_zeta, + polys_at_zeta_omega, + zeta, + zeta_omega, + } = pcs_openings; + + let mut coord_vecs = vec![vec![zeta]; polys_at_zeta.len()]; + coord_vecs.push(vec![zeta_omega]); + let polys = [ + polys_at_zeta, + polys_at_zeta_omega + ].concat(); + + let coord_sets: Vec> = coord_vecs + .iter() + .cloned() + .map(BTreeSet::from_iter) + .collect(); + + let todo = Coeffs(C::ScalarField::rand(rng), C::ScalarField::rand(rng)); + let t_open = start_timer!(|| format!( + "Opening IPA ring-proof with shplonk, {} polys, max_degree = {}", + polys.len(), + polys[polys.len() - 2].degree() // the quotient + )); + let pcs_opening_proof = Shplonk::>::open_many( + &self.pcs_params, + &polys, + &coord_sets, + witness.parent_r, + &mut todo.clone(), + ); + end_timer!(t_open); + + let proof = LevelProof { + piop_proof, + pcs_opening_proof, + todo, + }; + (blinded_pk, proof) + } +} \ No newline at end of file diff --git a/pasta-tree/src/level/verifier.rs b/pasta-tree/src/level/verifier.rs new file mode 100644 index 0000000..728941f --- /dev/null +++ b/pasta-tree/src/level/verifier.rs @@ -0,0 +1,73 @@ +use ark_ec::CurveGroup; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_std::{end_timer, start_timer}; +use w3f_pcs::pcs::PcsParams; +use w3f_pcs::shplonk::Shplonk; +use w3f_plonk_common::piop::VerifierPiop; +use w3f_plonk_common::verifier::{PcsOpeningAt2Points, PlonkVerifier}; +use w3f_ring_proof::{ArkTranscript, FixedColumnsCommitted, VerifierKey}; +use w3f_ring_proof::piop::verifier::PiopVerifier; +use crate::ipa_hiding::HidingIpa; +use crate::level::{CycleSideParams, IPACommitment, LevelProof}; + +impl> CycleSideParams { + pub fn verify_level(&self, parent: FixedColumnsCommitted>, blinded_child: Affine, level_proof: LevelProof) -> bool { + let verifier_key: VerifierKey> = VerifierKey { + pcs_raw_vk: self.pcs_params.raw_vk(), + fixed_columns_committed: parent.clone(), + }; + let plonk_verifier: PlonkVerifier, _> = PlonkVerifier::init(self.pcs_params.vk(), &verifier_key, ArkTranscript::new(b"pasta-tree-level-proof")); + + let LevelProof { + piop_proof, + pcs_opening_proof, + mut todo, + } = level_proof; + + let (challenges, mut rng) = plonk_verifier.restore_challenges( + &blinded_child, + &piop_proof, + // '1' accounts for the quotient polynomial that is aggregated together with the columns + PiopVerifier::, Affine>::N_COLUMNS + 1, + PiopVerifier::, Affine>::N_CONSTRAINTS, + ); + let seed = self.piop_params.seed; + let seed_plus_result = (seed + blinded_child).into_affine(); + let domain_at_zeta = self.piop_params.domain.evaluate(challenges.zeta); + let piop = PiopVerifier::<_, _, Affine>::init( + domain_at_zeta, + parent, + piop_proof.column_commitments.clone(), + piop_proof.columns_at_zeta.clone(), + (seed.x, seed.y), + (seed_plus_result.x, seed_plus_result.y), + ); + + let PcsOpeningAt2Points { + open_at_zeta, + open_at_zeta_omega, + zeta, + zeta_omega, + vals_at_zeta, + vals_at_zeta_omega + } = plonk_verifier.evaluate_piop(piop, piop_proof, challenges); + + let mut coord_vecs = vec![vec![zeta]; open_at_zeta.len()]; + coord_vecs.push(vec![zeta_omega]); + let polys = [open_at_zeta, open_at_zeta_omega].concat(); + let mut vals: Vec<_> = vals_at_zeta.into_iter().map(|v| vec![v]).collect(); + vals.push(vals_at_zeta_omega); + let t_verify = start_timer!(|| "Verifying IPA shplonk opening"); + let valid = Shplonk::>::verify_many( + &self.pcs_params.vk(), + &polys, + pcs_opening_proof, + &coord_vecs, + &vals, + &mut todo, + ); + end_timer!(t_verify); + + valid + } +} \ No newline at end of file diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index de2d71b..7511cd0 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -4,9 +4,11 @@ use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; use ark_poly::{EvaluationDomain, Evaluations, Radix2EvaluationDomain}; use ark_std::rand::Rng; +use w3f_pcs::aggregation::multiple::Transcript; use w3f_pcs::pcs::PCS; pub mod ipa_hiding; +pub mod level; pub struct CycleSideParams { ipa_pcs: HidingIpa, @@ -123,6 +125,20 @@ where } } +#[derive(Clone)] +pub struct Coeffs(F, F); +impl> Transcript for Coeffs { + fn get_gamma(&mut self) -> F { + self.0 + } + + fn commit_to_q(&mut self, _q: &CS::C) {} + + fn get_zeta(&mut self) -> F { + self.1 + } +} + #[cfg(test)] mod tests { use super::*; @@ -160,11 +176,9 @@ mod tests { #[cfg(feature = "parallel")] use rayon::prelude::*; - type PallasIPA = IPA; type PallasC = WrappedAffine; - #[test] fn test_membership_witness() { let rng = &mut test_rng(); @@ -237,19 +251,6 @@ mod tests { assert!(valid); } - struct Coeffs(F, F); - impl> Transcript for Coeffs { - fn get_gamma(&mut self) -> F { - self.0 - } - - fn commit_to_q(&mut self, _q: &CS::C) {} - - fn get_zeta(&mut self) -> F { - self.1 - } - } - // cargo test test_pasta_ring_shplonk --release --features="print-trace" -- --show-output #[test] fn test_pasta_ring_shplonk() { From dd36971ca6e6556de20a1d0ff6d669a7f9186434 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Fri, 15 May 2026 07:46:54 +0300 Subject: [PATCH 18/36] benches added --- pasta-tree/src/level/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index 64c0a4f..50bca31 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -103,7 +103,7 @@ mod tests { use ark_pallas::PallasConfig; use ark_poly::DenseUVPolynomial; use ark_std::rand::Rng; - use ark_std::{test_rng, UniformRand}; + use ark_std::{end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; use w3f_pcs::pcs::PCS; use w3f_plonk_common::test_helpers::random_vec; @@ -156,8 +156,14 @@ mod tests { let root_fc = l1_vk.fixed_columns_committed; let leaf = l2_nodes.siblings[l2_nodes.i]; + let capacity = c0_params.piop_params.keyset_part_size; + let t_prove = start_timer!(|| format!("Proving 1st level of a curve tree, domain_size={domain_size}, capacity={capacity}")); let (l1_node_blinded, l1_proof) = c0_params.prove_level(&l1_nodes, rng); + end_timer!(t_prove); + + let t_verify = start_timer!(|| format!("Verifying a single-level proof")); assert!(c0_params.verify_level(root_fc, l1_node_blinded, l1_proof)); + end_timer!(t_verify); let l2_nodes_parent_r = l1_nodes.child_r; let (l2_column, l2_vk) = c1_params.commit_child_nodes(l2_nodes.siblings.as_slice(), l2_nodes_parent_r); @@ -165,10 +171,16 @@ mod tests { assert_eq!(l1_node_fc.points[0].0, l1_node_blinded); l2_nodes.parent_r = l2_nodes_parent_r; + let t_prove = start_timer!(|| format!("Proving 2nd level of a curve tree, domain_size={domain_size}, capacity={capacity}")); let (blinded_leaf, l2_proof) = c1_params.prove_level(&l2_nodes, rng); + end_timer!(t_prove); + + let t_verify = start_timer!(|| format!("Verifying a single-level proof")); assert!(c1_params.verify_level(l1_node_fc, blinded_leaf, l2_proof)); + end_timer!(t_verify); } + // cargo test test_level_proof --release --features="print-trace" -- --show-output #[test] fn test_level_proof() { _test_level_proof::<_, _, PallasConfig, VestaConfig>() From aaa7647e2f1725313a9f5a1d2ded0a4d3a935aee Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sat, 16 May 2026 22:45:15 +0300 Subject: [PATCH 19/36] auth_path cleaned up --- pasta-tree/src/auth_path/blinded.rs | 39 ++++++++ pasta-tree/src/auth_path/mod.rs | 4 + pasta-tree/src/auth_path/node.rs | 85 +++++++++++++++++ pasta-tree/src/auth_path/path.rs | 137 ++++++++++++++++++++++++++++ pasta-tree/src/level/mod.rs | 7 +- pasta-tree/src/lib.rs | 110 +--------------------- 6 files changed, 272 insertions(+), 110 deletions(-) create mode 100644 pasta-tree/src/auth_path/blinded.rs create mode 100644 pasta-tree/src/auth_path/mod.rs create mode 100644 pasta-tree/src/auth_path/node.rs create mode 100644 pasta-tree/src/auth_path/path.rs diff --git a/pasta-tree/src/auth_path/blinded.rs b/pasta-tree/src/auth_path/blinded.rs new file mode 100644 index 0000000..70d09d0 --- /dev/null +++ b/pasta-tree/src/auth_path/blinded.rs @@ -0,0 +1,39 @@ +use ark_ec::CurveGroup; +use ark_ff::PrimeField; +use crate::auth_path::node::LevelWitnessWithBlinding; +use crate::{CycleParams, CycleSide}; + +pub struct AuthenticationPathWithBlinding { + pub(crate) c0_path: Vec>, + pub(crate) c1_path: Vec>, +} + +impl AuthenticationPathWithBlinding +where + F0: PrimeField, + F1: PrimeField, + C0: CurveGroup, + C1: CurveGroup, +{ + pub(crate) fn compute_root(&self, params: &CycleParams) -> Result, ()> { + let mut path_0_iter = self.c0_path.iter(); + let c0_nodes = path_0_iter.next().unwrap(); + let mut parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + for c1_nodes in self.c1_path.iter() { + let next_c1_path_node = c1_nodes.blinded_path_node(¶ms.c1_params.ipa_pcs)?; + debug_assert_eq!(parent_on_c1, next_c1_path_node); + (parent_on_c1 == next_c1_path_node).ok_or(())?; + let parent_on_c0 = c1_nodes.compute_parent(¶ms.c0_params).unwrap().into_affine(); + match path_0_iter.next() { + Some(c0_nodes) => { + let next_c0_path_node = c0_nodes.blinded_path_node(¶ms.c0_params.ipa_pcs)?; + debug_assert_eq!(parent_on_c0, next_c0_path_node); + (parent_on_c0 == next_c0_path_node).ok_or(())?; + parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + } + None => return Ok(CycleSide::C0(parent_on_c0)) + } + } + Ok(CycleSide::C1(parent_on_c1)) + } +} \ No newline at end of file diff --git a/pasta-tree/src/auth_path/mod.rs b/pasta-tree/src/auth_path/mod.rs new file mode 100644 index 0000000..1715905 --- /dev/null +++ b/pasta-tree/src/auth_path/mod.rs @@ -0,0 +1,4 @@ +pub mod node; +pub mod path; +mod blinded; + diff --git a/pasta-tree/src/auth_path/node.rs b/pasta-tree/src/auth_path/node.rs new file mode 100644 index 0000000..c769399 --- /dev/null +++ b/pasta-tree/src/auth_path/node.rs @@ -0,0 +1,85 @@ +use crate::ipa_hiding::HidingIpa; +use crate::CycleSideParams; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_ff::{PrimeField, Zero}; + +/// An element of a tree authentication path. A node on the path together with it's sibling. +/// `path_node = self.siblings[self.path_node_idx]` is the node on the path. +/// The next node on the path to the root can be computed as `parent = commit(self.siblings)`. +// TODO: the minimal witness is x-coords of the siblings, and y_i +#[derive(Clone, Debug)] +pub struct LevelWitness { + siblings: Vec, + path_node_idx: usize, +} + +impl LevelWitness { + pub(crate) fn new(siblings: Vec, path_node_idx: usize) -> Result { + debug_assert!(path_node_idx < siblings.len()); + (path_node_idx < siblings.len()).ok_or(())?; + Ok(Self { + siblings, + path_node_idx, + }) + } + + fn x_coords(&self) -> Vec { + self.siblings.iter() + .map(|p| p.x()) + .flatten() + .collect() + } + + pub(crate) fn path_node(&self) -> G { + self.siblings[self.path_node_idx] + } + + pub(crate) fn with_blinding(&self, self_bf: G::ScalarField, parent_bf: G::BaseField) -> LevelWitnessWithBlinding { + LevelWitnessWithBlinding { + level_witness: self.clone(), + bf: self_bf, + parent_bf, + } + } + + pub(crate) fn compute_parent>(&self, params: &CycleSideParams) -> Result + where + G::BaseField: PrimeField, + { + self.compute_parent_with_bf(params, C::ScalarField::zero()) + } + + fn compute_parent_with_bf>(&self, params: &CycleSideParams, bf: C::ScalarField) -> Result + where + G::BaseField: PrimeField, + { + params.commit_node(self.x_coords(), bf) + } +} + + +/// NB! It is not "blinded", meaning that the blinding factor hasn't been applied. +pub struct LevelWitnessWithBlinding { + level_witness: LevelWitness, + /// the verifier gets `Ci' = siblings[i] + bf.H` + bf: G::ScalarField, + /// Let `Ci = c1.G1 + ... + cm.Gm` -- the non-hiding commitment to a level. + /// Provided that, instead, the verifier gets `Ci' = Ci + bf.H`, + /// when opening the commitment, the prover interprets it as a hiding commitment + /// and needs to know the parent's blinding factor to open to the same values. + /// The root is not blinded, so `parent_bf = 0` for the level below the root. + parent_bf: G::BaseField, // = C::ScalarField +} + +impl LevelWitnessWithBlinding { + pub(crate) fn blinded_path_node(&self, ipa_pcs: &HidingIpa) -> Result { + Ok(ipa_pcs.reblind(self.level_witness.path_node(), G::ScalarField::zero(), self.bf)?.0) + } + + pub(crate) fn compute_parent>(&self, params: &CycleSideParams) -> Result + where + G::BaseField: PrimeField, + { + self.level_witness.compute_parent_with_bf(params, self.parent_bf) + } +} \ No newline at end of file diff --git a/pasta-tree/src/auth_path/path.rs b/pasta-tree/src/auth_path/path.rs new file mode 100644 index 0000000..347b429 --- /dev/null +++ b/pasta-tree/src/auth_path/path.rs @@ -0,0 +1,137 @@ +use ark_ec::CurveGroup; +use ark_ff::PrimeField; +use ark_std::rand::Rng; +use crate::auth_path::node::LevelWitness; +use crate::{CycleSide, CycleParams}; +use crate::auth_path::blinded::AuthenticationPathWithBlinding; + +/// A non-hiding authentication path from a leaf to the root, split between the curves of the cycle. +/// For each tree level (excluding the root), the corresponding element of the authentication path (`LevelWitness`) +/// contains the root-path node at that level, together with all its siblings. +/// That allows to recompute the parent -- the path node at the *previous* level, up to the root. +/// `path_0[0]` contains the leaf (with its siblings). +/// `commit(path_0[k].siblings) = path_1[k].siblings[path_1[k].i]`, if `path_1[k]` exists, +/// otherwise it's the root. +pub struct AuthenticationPath { + /// Nodes on the `C0` curve. + c0_path: Vec>, + /// Nodes on the `C1` curve. + c1_path: Vec>, +} + +impl AuthenticationPath +where + F0: PrimeField, + F1: PrimeField, + C0: CurveGroup, + C1: CurveGroup, +{ + fn with_blinding(&self, rng: &mut R) -> AuthenticationPathWithBlinding { + let mut path_0 = Vec::with_capacity(self.c0_path.len()); + let mut path_1 = Vec::with_capacity(self.c1_path.len()); + + let mut c0_path_iter = self.c0_path.iter(); + let mut c0_nodes = c0_path_iter.next().unwrap(); // shouldn't be empty + let mut c0_bf = C0::ScalarField::rand(rng); + for c1_nodes in self.c1_path.iter() { + let c1_bf = C1::ScalarField::rand(rng); + path_0.push(c0_nodes.with_blinding(c0_bf, c1_bf)); + match c0_path_iter.next() { + Some(c0_nodes_) => { + c0_nodes = c0_nodes_; + c0_bf = C0::ScalarField::rand(rng); + path_1.push(c1_nodes.with_blinding(c1_bf, c0_bf)); + } + None => { + // then the parent of `c1_nodes` is the root + c0_bf = C0::ScalarField::zero(); // `c0_bf = 0` indicates this case + let root_bf = c0_bf; + path_1.push(c1_nodes.with_blinding(c1_bf, root_bf)); + } + } + } + if !c0_bf.is_zero() { + // then `c0_nodes` are the level below the root + let root_bf = C1::ScalarField::zero(); + path_0.push(c0_nodes.with_blinding(c0_bf, root_bf)); + } + + debug_assert_eq!(path_0.len(), self.c0_path.len()); + debug_assert_eq!(path_1.len(), self.c1_path.len()); + + AuthenticationPathWithBlinding { + c0_path: path_0, + c1_path: path_1, + } + } + + fn get_leaf(&self) -> C0::Affine { + self.c0_path[0].path_node() + } + + fn compute_root(&self, params: &CycleParams) -> Result, ()> { + let mut c0_path_iter = self.c0_path.iter(); + let c0_nodes = c0_path_iter.next().unwrap(); // shouldn't be empty + let mut parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + for c1_nodes in self.c1_path.iter() { + debug_assert_eq!(parent_on_c1, c1_nodes.path_node()); + (parent_on_c1 == c1_nodes.path_node()).ok_or(())?; + let parent_on_c0 = c1_nodes.compute_parent(¶ms.c0_params).unwrap().into_affine(); + match c0_path_iter.next() { + Some(c0_nodes) => { + debug_assert_eq!(parent_on_c0, c0_nodes.path_node()); + (parent_on_c0 == c0_nodes.path_node()).ok_or(())?; + parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + } + None => return Ok(CycleSide::C0(parent_on_c0)) + } + } + Ok(CycleSide::C1(parent_on_c1)) + } +} + +#[cfg(test)] +mod tests { + use ark_poly::EvaluationDomain; + use ark_std::test_rng; + use w3f_plonk_common::test_helpers::random_vec; + use super::*; + + #[test] + fn test_auth_path() { + let rng = &mut test_rng(); + + let params = CycleParams::::setup(9, rng).unwrap(); + + let c0_capacity = params.c0_params.domain.size(); + let leaves = random_vec::(c0_capacity, rng); + let leaf_index = rng.gen_range(0..c0_capacity); + let leaf = leaves[leaf_index]; + let leaves = LevelWitness::new(leaves, leaf_index).unwrap(); + let innner_parent = leaves.compute_parent(¶ms.c1_params).unwrap().into_affine(); + + let c1_capacity = params.c1_params.domain.size(); + let parent_index = rng.gen_range(0..c1_capacity); + let mut inner_nodes = random_vec::(c1_capacity, rng); + inner_nodes[parent_index] = innner_parent; + let inner_nodes = LevelWitness::new(inner_nodes, parent_index).unwrap(); + let root = inner_nodes.compute_parent(¶ms.c0_params).unwrap().into_affine(); + + let path = AuthenticationPath { + c0_path: vec![leaves.clone()], + c1_path: vec![inner_nodes.clone()], + }; + + assert_eq!(path.get_leaf(), leaf); + match path.compute_root(¶ms).unwrap() { + CycleSide::C0(root_) => assert_eq!(root_, root), + _ => panic!() + } + + let path_with_bfs = path.with_blinding(rng); + match path_with_bfs.compute_root(¶ms).unwrap() { + CycleSide::C0(root_) => assert_eq!(root_, root), + _ => panic!() + } + } +} \ No newline at end of file diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index 50bca31..6d5884e 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -97,15 +97,13 @@ impl> CycleSideParams< #[cfg(test)] mod tests { use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; - use ark_ec::{AffineRepr, CurveGroup}; + use ark_ec::CurveGroup; use ark_ff::PrimeField; - use ark_ff::{Field, Zero}; + use ark_ff::Zero; use ark_pallas::PallasConfig; - use ark_poly::DenseUVPolynomial; use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; - use w3f_pcs::pcs::PCS; use w3f_plonk_common::test_helpers::random_vec; use crate::level::{CycleParams, CycleSideParams}; @@ -181,6 +179,7 @@ mod tests { } // cargo test test_level_proof --release --features="print-trace" -- --show-output + // cargo test test_level_proof --release --features="print-trace parallel" -- --show-output #[test] fn test_level_proof() { _test_level_proof::<_, _, PallasConfig, VestaConfig>() diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 7511cd0..a6cb62a 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,6 +1,7 @@ #![feature(bool_to_result)] + use crate::ipa_hiding::HidingIpa; -use ark_ec::{AffineRepr, CurveGroup}; +use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::{EvaluationDomain, Evaluations, Radix2EvaluationDomain}; use ark_std::rand::Rng; @@ -9,6 +10,7 @@ use w3f_pcs::pcs::PCS; pub mod ipa_hiding; pub mod level; +mod auth_path; pub struct CycleSideParams { ipa_pcs: HidingIpa, @@ -56,75 +58,11 @@ impl CycleParams { } } -#[derive(Clone)] -pub struct LevelWitness { - siblings: Vec, - i: usize, -} - -impl LevelWitness { - fn x_coords(&self) -> Vec { - self.siblings.iter() - .map(|p| p.x()) - .flatten() - .collect() - } - - fn path_node(&self) -> G { - self.siblings[self.i] - } - - fn commit_node>(&self, params: &CycleSideParams, blinding: C::ScalarField) -> Result - where - G::BaseField: PrimeField, - { - params.commit_node(self.x_coords(), blinding) - } -} - -/// Leaves are points on `C0` -struct MembershipWitness { - path_0: Vec>, - path_1: Vec>, -} - -enum CycleCurve { +enum CycleSide { C0(C0), C1(C1), } -impl MembershipWitness -where - F0: PrimeField, - F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, -{ - fn validate(&self, params: &CycleParams) -> Result<(C0::Affine, CycleCurve), ()> { - let mut path_0_iter = self.path_0.iter(); - let leaf_node = path_0_iter.next().unwrap(); - let leaf = leaf_node.path_node(); - - let node_0 = leaf_node; - let mut parent_on_c1 = node_0.commit_node(¶ms.c1_params, C1::ScalarField::zero()).unwrap().into_affine(); - let mut root = CycleCurve::C1(parent_on_c1); - for node_1 in self.path_1.iter() { - assert_eq!(parent_on_c1, node_1.path_node()); - let parent_on_c0 = node_1.commit_node(¶ms.c0_params, C0::ScalarField::zero()).unwrap().into_affine(); - root = CycleCurve::C0(parent_on_c0); - match path_0_iter.next() { - Some(node_0) => { - assert_eq!(parent_on_c0, node_0.path_node()); - parent_on_c1 = node_0.commit_node(¶ms.c1_params, C1::ScalarField::zero()).unwrap().into_affine(); - root = CycleCurve::C1(parent_on_c1); - }, - None => break - } - } - Ok((leaf, root)) - } -} - #[derive(Clone)] pub struct Coeffs(F, F); impl> Transcript for Coeffs { @@ -142,7 +80,6 @@ impl> Transcript for Coeffs { #[cfg(test)] mod tests { use super::*; - use crate::CycleParams; use ark_ec::scalar_mul::glv::GLVConfig; use ark_ec::scalar_mul::wnaf::WnafContext; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; @@ -158,7 +95,6 @@ mod tests { use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; use std::collections::BTreeSet; - use w3f_pcs::aggregation::multiple::Transcript; use w3f_pcs::pcs::ipa::IPA; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; use w3f_pcs::pcs::PcsParams; @@ -179,44 +115,6 @@ mod tests { type PallasIPA = IPA; type PallasC = WrappedAffine; - #[test] - fn test_membership_witness() { - let rng = &mut test_rng(); - - let params = CycleParams::::setup(9, rng).unwrap(); - - let c0_capacity = params.c0_params.domain.size(); - let leaves = random_vec::(c0_capacity, rng); - let leaf_index = rng.gen_range(0..c0_capacity); - let node_0 = LevelWitness { - siblings: leaves, - i: leaf_index, - }; - let parent = node_0.commit_node(¶ms.c1_params, ark_vesta::Fr::zero()).unwrap().into_affine(); - - let c1_capacity = params.c1_params.domain.size(); - let parent_index = rng.gen_range(0..c1_capacity); - let mut inner_nodes = random_vec::(c1_capacity, rng); - inner_nodes[parent_index] = parent; - let node_1 = LevelWitness { - siblings: inner_nodes, - i: parent_index, - }; - let root = node_1.commit_node(¶ms.c0_params, ark_pallas::Fr::zero()).unwrap().into_affine(); - - let path = MembershipWitness { - path_0: vec![node_0.clone()], - path_1: vec![node_1.clone()], - }; - - let (leaf, root_) = path.validate(¶ms).unwrap(); - assert_eq!(leaf, node_0.path_node()); - match root_ { - CycleCurve::C0(c0) => assert_eq!(c0, root), - _ => panic!() - } - } - // cargo test test_pasta_ring_plonk --release --features="print-trace" -- --show-output #[test] fn test_pasta_ring_plonk() { From 17d9b866d96ef3e3c2c6badaa0f9f3f85d77beac Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 07:21:31 +0300 Subject: [PATCH 20/36] master merged --- Cargo.toml | 2 +- w3f-ring-proof/benches/ring_proof.rs | 30 +++++++++---------- w3f-ring-proof/src/lib.rs | 30 +++++++++---------- .../src/multi_ring_batch_verifier.rs | 10 +++---- w3f-ring-proof/src/piop/mod.rs | 8 ++--- w3f-ring-proof/src/piop/prover.rs | 8 ++--- w3f-ring-proof/src/piop/verifier.rs | 4 +-- w3f-ring-proof/src/ring_prover.rs | 6 ++-- w3f-ring-proof/src/ring_verifier.rs | 8 ++--- 9 files changed, 53 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2acc82..309ecff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ resolver = "2" members = [ # "evm-vrfier", - "pasta-tree", +# "pasta-tree", "w3f-plonk-common", "w3f-ring-proof", # "w3f-ring-vrf-snark", diff --git a/w3f-ring-proof/benches/ring_proof.rs b/w3f-ring-proof/benches/ring_proof.rs index 9ae8a9a..aaf9e86 100644 --- a/w3f-ring-proof/benches/ring_proof.rs +++ b/w3f-ring-proof/benches/ring_proof.rs @@ -2,7 +2,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criteri use ark_bls12_381::Bls12_381; use ark_ec::CurveGroup; -use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, Fq, Fr, SWAffine}; +use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, Fq, Fr, EdwardsAffine}; use ark_serialize::CanonicalSerialize; use ark_std::ops::Mul; use ark_std::rand::Rng; @@ -25,9 +25,9 @@ fn setup( let setup_degree = 3 * domain_size; let pcs_params = CS::setup(setup_degree, rng); let domain = Domain::new(domain_size, true); - let h = SWAffine::rand(rng); - let seed = SWAffine::rand(rng); - let padding = SWAffine::rand(rng); + let h = EdwardsAffine::rand(rng); + let seed = EdwardsAffine::rand(rng); + let padding = EdwardsAffine::rand(rng); let piop_params = PiopParams::setup(domain, h, seed, padding); (pcs_params, piop_params) } @@ -37,7 +37,7 @@ fn make_transcript() -> ArkTranscript { } /// Get the Pedersen blinding base H from the PIOP params (first element of the power-of-2 multiples). -fn get_h(piop_params: &PiopParams) -> SWAffine { +fn get_h(piop_params: &PiopParams) -> EdwardsAffine { piop_params.power_of_2_multiples_of_h()[0] } @@ -45,9 +45,9 @@ fn get_h(piop_params: &PiopParams) -> SWAffine { fn generate_proof( piop_params: &PiopParams, pcs_params: &>::Params, - pks: &[SWAffine], + pks: &[EdwardsAffine], rng: &mut impl Rng, -) -> (SWAffine, RingProof) { +) -> (EdwardsAffine, RingProof) { let h = get_h(piop_params); let prover_idx = rng.gen_range(0..pks.len()); let (prover_key, _) = index::<_, CS, _>(pcs_params, piop_params, pks); @@ -86,7 +86,7 @@ fn bench_index(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); group.bench_with_input(BenchmarkId::new("full_keyset", n), &n, |b, _| { b.iter(|| index::<_, CS, _>(&pcs_params, &piop_params, &pks)); @@ -104,7 +104,7 @@ fn bench_prove(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (prover_key, _) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); let prover_idx = rng.gen_range(0..keyset_size); @@ -132,7 +132,7 @@ fn bench_verify(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (blinded_pk, proof) = generate_proof(&piop_params, &pcs_params, &pks, rng); let (_, verifier_key) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); @@ -154,11 +154,11 @@ fn bench_verify_batch_sequential(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); // Pre-generate proofs for the largest batch. let max_batch = 32; - let claims: Vec<(SWAffine, RingProof)> = (0..max_batch) + let claims: Vec<(EdwardsAffine, RingProof)> = (0..max_batch) .map(|_| generate_proof(&piop_params, &pcs_params, &pks, rng)) .collect(); @@ -188,10 +188,10 @@ fn bench_verify_batch_kzg(c: &mut Criterion) { let n = 1usize << log_n; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let max_batch = 32; - let claims: Vec<(SWAffine, RingProof)> = (0..max_batch) + let claims: Vec<(EdwardsAffine, RingProof)> = (0..max_batch) .map(|_| generate_proof(&piop_params, &pcs_params, &pks, rng)) .collect(); @@ -224,7 +224,7 @@ fn bench_proof_size(c: &mut Criterion) { let n = 1usize << 10; let (pcs_params, piop_params) = setup(rng, n); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (_, proof) = generate_proof(&piop_params, &pcs_params, &pks, rng); diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 67cdf8a..19beb47 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ff::PrimeField; use ark_serialize::CanonicalSerialize; use ark_std::rand::{Rng, RngCore}; @@ -51,10 +51,10 @@ impl ArkTranscript { } } -pub fn test_setup, G: SWCurveConfig>( +pub fn test_setup, G: TECurveConfig>( rng: &mut R, domain_size: usize, -) -> (CS::Params, PiopParams) { +) -> (CS::Params, PiopParams>) { let setup_degree = 3 * domain_size; let pcs_params = CS::setup(setup_degree, rng); let domain = Domain::new(domain_size, true); @@ -69,7 +69,7 @@ pub fn test_setup, G: SWCurveConfig ( RingVerifier, - Vec<(SWAffine, RingProof)>, + Vec<(EdwardsAffine, RingProof)>, ) { let rng = &mut test_rng(); let (pcs_params, piop_params) = setup::<_, CS>(rng, domain_size); let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (prover_key, verifier_key) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); let prover = RingProver::init( @@ -113,7 +113,7 @@ mod tests { let t_prove = start_timer!(|| { format!("Proving {batch_size} KZG ring-proofs with plonk, domain={domain_size}, max_keys={keyset_size}") }); - let claims: Vec<(SWAffine, RingProof)> = (0..batch_size) + let claims: Vec<(EdwardsAffine, RingProof)> = (0..batch_size) .map(|_| { let pk_idx = rng.gen_range(0..keyset_size); let r = Fr::rand(rng); @@ -154,7 +154,7 @@ mod tests { let max_keyset_size = piop_params.keyset_part_size; let keyset_size: usize = rng.gen_range(0..max_keyset_size); - let pks = random_vec::(keyset_size, rng); + let pks = random_vec::(keyset_size, rng); let (_, verifier_key) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks); @@ -175,9 +175,9 @@ mod tests { let pcs_params = CS::setup(setup_degree, rng); let domain = Domain::new(domain_size, true); - let h = SWAffine::rand(rng); - let seed = SWAffine::rand(rng); - let padding = SWAffine::rand(rng); + let h = EdwardsAffine::rand(rng); + let seed = EdwardsAffine::rand(rng); + let padding = EdwardsAffine::rand(rng); let piop_params = PiopParams::setup(domain, h, seed, padding); (pcs_params, piop_params) @@ -223,18 +223,18 @@ mod tests { // Ring A let keyset_size_a = piop_params.keyset_part_size; - let pks_a = random_vec::(keyset_size_a, rng); + let pks_a = random_vec::(keyset_size_a, rng); let (prover_key_a, verifier_key_a) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks_a); // Ring B (smaller keyset) let keyset_size_b = piop_params.keyset_part_size / 2; - let pks_b = random_vec::(keyset_size_b, rng); + let pks_b = random_vec::(keyset_size_b, rng); let (prover_key_b, verifier_key_b) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks_b); - let mut generate_claims = |prover_key: &ProverKey, SWAffine>, - pks: &[SWAffine], + let mut generate_claims = |prover_key: &ProverKey, EdwardsAffine>, + pks: &[EdwardsAffine], keyset_size: usize| { (0..proofs_per_ring) .map(|_| { diff --git a/w3f-ring-proof/src/multi_ring_batch_verifier.rs b/w3f-ring-proof/src/multi_ring_batch_verifier.rs index 1059b5a..2e8fd81 100644 --- a/w3f-ring-proof/src/multi_ring_batch_verifier.rs +++ b/w3f-ring-proof/src/multi_ring_batch_verifier.rs @@ -1,5 +1,5 @@ use ark_ec::pairing::Pairing; -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::CurveGroup; use ark_std::rand::RngCore; use w3f_pcs::pcs::kzg::params::KzgVerifierKey; @@ -18,7 +18,7 @@ use crate::RingProof; pub struct BatchItem where E: Pairing, - J: SWCurveConfig, + J: TECurveConfig, { piop: PiopVerifier as PCS>::C, Affine>, proof: RingProof>, @@ -29,7 +29,7 @@ where impl BatchItem where E: Pairing, - J: SWCurveConfig, + J: TECurveConfig, { /// Prepares a ring proof for batch verification without accumulating it. /// @@ -113,7 +113,7 @@ where proof: RingProof>, result: Affine, ) where - J: SWCurveConfig, + J: TECurveConfig, { self.push_prepared(BatchItem::new(verifier, proof, result)); } @@ -128,7 +128,7 @@ where /// then pushed sequentially here. pub fn push_prepared(&mut self, item: BatchItem) where - J: SWCurveConfig, + J: TECurveConfig, { let mut ts = self.transcript.clone(); ts._add_serializable(b"batch-entropy", &item.entropy); diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index 861ff95..1b8c375 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::short_weierstrass::{Affine, SWCurveConfig}; +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, G: SWCurveConfig>( + pub fn from_ring, G: TECurveConfig>( ring: &Ring, ) -> Self { let cx = WrappedAffine(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,7 +181,7 @@ impl VerifierKey> { } } -pub fn index, Curve: SWCurveConfig>( +pub fn index, Curve: TECurveConfig>( pcs_params: &CS::Params, piop_params: &PiopParams>, keys: &[Affine], diff --git a/w3f-ring-proof/src/piop/prover.rs b/w3f-ring-proof/src/piop/prover.rs index 8ceacae..ddec2ba 100644 --- a/w3f-ring-proof/src/piop/prover.rs +++ b/w3f-ring-proof/src/piop/prover.rs @@ -1,4 +1,4 @@ -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ff::PrimeField; use ark_poly::univariate::DensePolynomial; use ark_poly::Evaluations; @@ -22,7 +22,7 @@ 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>, @@ -38,7 +38,7 @@ pub struct PiopProver> { cond_add_acc_y: FixedCells, } -impl> PiopProver { +impl> PiopProver { pub fn build( params: &PiopParams>, fixed_columns: FixedColumns>, @@ -90,7 +90,7 @@ impl ProverPiop for PiopProver where F: PrimeField, C: Commitment, - Curve: SWCurveConfig, + Curve: TECurveConfig, { type Commitments = RingCommitments; type Evaluations = RingEvaluations; diff --git a/w3f-ring-proof/src/piop/verifier.rs b/w3f-ring-proof/src/piop/verifier.rs index e5ec773..8eb663f 100644 --- a/w3f-ring-proof/src/piop/verifier.rs +++ b/w3f-ring-proof/src/piop/verifier.rs @@ -1,4 +1,4 @@ -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_std::marker::PhantomData; @@ -101,7 +101,7 @@ impl, P: AffineRepr> PiopVerifier } } -impl, Jubjub: SWCurveConfig> VerifierPiop +impl, Jubjub: TECurveConfig> VerifierPiop for PiopVerifier> { const N_CONSTRAINTS: usize = 7; diff --git a/w3f-ring-proof/src/ring_prover.rs b/w3f-ring-proof/src/ring_prover.rs index 48136d2..5c7b6cb 100644 --- a/w3f-ring-proof/src/ring_prover.rs +++ b/w3f-ring-proof/src/ring_prover.rs @@ -1,4 +1,4 @@ -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ff::PrimeField; use w3f_pcs::pcs::PCS; use w3f_plonk_common::piop::ProverPiop; @@ -13,7 +13,7 @@ pub struct RingProver where F: PrimeField, CS: PCS, - Curve: SWCurveConfig, + Curve: TECurveConfig, T: PlonkTranscript, { piop_params: PiopParams>, @@ -29,7 +29,7 @@ impl RingProver where F: PrimeField, CS: PCS, - Curve: SWCurveConfig, + Curve: TECurveConfig, T: PlonkTranscript, { pub fn init( diff --git a/w3f-ring-proof/src/ring_verifier.rs b/w3f-ring-proof/src/ring_verifier.rs index 09ebf9c..d406f3d 100644 --- a/w3f-ring-proof/src/ring_verifier.rs +++ b/w3f-ring-proof/src/ring_verifier.rs @@ -1,5 +1,5 @@ use ark_ec::pairing::Pairing; -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::CurveGroup; use ark_ff::PrimeField; use w3f_pcs::pcs::kzg::KZG; @@ -18,7 +18,7 @@ pub struct RingVerifier where F: PrimeField, CS: PCS, - Jubjub: SWCurveConfig, + Jubjub: TECurveConfig, T: PlonkTranscript, { pub(crate) piop_params: PiopParams>, @@ -30,7 +30,7 @@ impl RingVerifier where F: PrimeField, CS: PCS, - Jubjub: SWCurveConfig, + Jubjub: TECurveConfig, T: PlonkTranscript, { pub fn init( @@ -98,7 +98,7 @@ where impl RingVerifier, J, T> where E: Pairing, - J: SWCurveConfig, + J: TECurveConfig, T: PlonkTranscript>, { /// Verifies a batch of proofs against this ring in a single batched From 37b03c57922f97ca5197a4e1e424ff263cce3a74 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 07:55:08 +0300 Subject: [PATCH 21/36] fmt --- w3f-ring-proof/benches/ring_proof.rs | 2 +- w3f-ring-proof/src/piop/mod.rs | 6 ++++-- w3f-ring-proof/src/piop/prover.rs | 17 +++++++---------- w3f-ring-proof/src/piop/verifier.rs | 8 ++++---- w3f-ring-proof/src/ring.rs | 25 +++++++------------------ 5 files changed, 23 insertions(+), 35 deletions(-) diff --git a/w3f-ring-proof/benches/ring_proof.rs b/w3f-ring-proof/benches/ring_proof.rs index aaf9e86..56f8158 100644 --- a/w3f-ring-proof/benches/ring_proof.rs +++ b/w3f-ring-proof/benches/ring_proof.rs @@ -2,7 +2,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criteri use ark_bls12_381::Bls12_381; use ark_ec::CurveGroup; -use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, Fq, Fr, EdwardsAffine}; +use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, EdwardsAffine, Fq, Fr}; use ark_serialize::CanonicalSerialize; use ark_std::ops::Mul; use ark_std::rand::Rng; diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index be4f173..39c406d 100644 --- a/w3f-ring-proof/src/piop/mod.rs +++ b/w3f-ring-proof/src/piop/mod.rs @@ -95,8 +95,10 @@ impl> FixedColumnsCommitted { } } -impl > Ring { - pub fn as_fixed_columns(&self) -> FixedColumnsCommitted> { +impl> Ring { + pub fn as_fixed_columns( + &self, + ) -> FixedColumnsCommitted> { let cx = WrappedAffine(self.cx); let cy = WrappedAffine(self.cy); FixedColumnsCommitted { 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 Date: Sun, 17 May 2026 08:13:28 +0300 Subject: [PATCH 22/36] generic-piop merged - 2 + fmt --- Cargo.toml | 2 +- pasta-tree/src/auth_path/blinded.rs | 35 +++++++--- pasta-tree/src/auth_path/mod.rs | 3 +- pasta-tree/src/auth_path/node.rs | 43 ++++++++---- pasta-tree/src/auth_path/path.rs | 53 +++++++++----- pasta-tree/src/ipa_hiding.rs | 64 +++++++++++------ pasta-tree/src/level/mod.rs | 104 +++++++++++++++++++--------- pasta-tree/src/level/prover.rs | 43 +++++++----- pasta-tree/src/level/verifier.rs | 27 +++++--- pasta-tree/src/lib.rs | 104 ++++++++++++++++------------ w3f-ring-proof/src/lib.rs | 19 +---- 11 files changed, 315 insertions(+), 182 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 309ecff..a2acc82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ resolver = "2" members = [ # "evm-vrfier", -# "pasta-tree", + "pasta-tree", "w3f-plonk-common", "w3f-ring-proof", # "w3f-ring-vrf-snark", diff --git a/pasta-tree/src/auth_path/blinded.rs b/pasta-tree/src/auth_path/blinded.rs index 70d09d0..95fec84 100644 --- a/pasta-tree/src/auth_path/blinded.rs +++ b/pasta-tree/src/auth_path/blinded.rs @@ -1,7 +1,7 @@ -use ark_ec::CurveGroup; -use ark_ff::PrimeField; use crate::auth_path::node::LevelWitnessWithBlinding; use crate::{CycleParams, CycleSide}; +use ark_ec::CurveGroup; +use ark_ff::PrimeField; pub struct AuthenticationPathWithBlinding { pub(crate) c0_path: Vec>, @@ -12,28 +12,41 @@ impl AuthenticationPathWithBlinding where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { - pub(crate) fn compute_root(&self, params: &CycleParams) -> Result, ()> { + pub(crate) fn compute_root( + &self, + params: &CycleParams, + ) -> Result, ()> { let mut path_0_iter = self.c0_path.iter(); let c0_nodes = path_0_iter.next().unwrap(); - let mut parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + let mut parent_on_c1 = c0_nodes + .compute_parent(¶ms.c1_params) + .unwrap() + .into_affine(); for c1_nodes in self.c1_path.iter() { let next_c1_path_node = c1_nodes.blinded_path_node(¶ms.c1_params.ipa_pcs)?; debug_assert_eq!(parent_on_c1, next_c1_path_node); (parent_on_c1 == next_c1_path_node).ok_or(())?; - let parent_on_c0 = c1_nodes.compute_parent(¶ms.c0_params).unwrap().into_affine(); + let parent_on_c0 = c1_nodes + .compute_parent(¶ms.c0_params) + .unwrap() + .into_affine(); match path_0_iter.next() { Some(c0_nodes) => { - let next_c0_path_node = c0_nodes.blinded_path_node(¶ms.c0_params.ipa_pcs)?; + let next_c0_path_node = + c0_nodes.blinded_path_node(¶ms.c0_params.ipa_pcs)?; debug_assert_eq!(parent_on_c0, next_c0_path_node); (parent_on_c0 == next_c0_path_node).ok_or(())?; - parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + parent_on_c1 = c0_nodes + .compute_parent(¶ms.c1_params) + .unwrap() + .into_affine(); } - None => return Ok(CycleSide::C0(parent_on_c0)) + None => return Ok(CycleSide::C0(parent_on_c0)), } } Ok(CycleSide::C1(parent_on_c1)) } -} \ No newline at end of file +} diff --git a/pasta-tree/src/auth_path/mod.rs b/pasta-tree/src/auth_path/mod.rs index 1715905..5a14038 100644 --- a/pasta-tree/src/auth_path/mod.rs +++ b/pasta-tree/src/auth_path/mod.rs @@ -1,4 +1,3 @@ +mod blinded; pub mod node; pub mod path; -mod blinded; - diff --git a/pasta-tree/src/auth_path/node.rs b/pasta-tree/src/auth_path/node.rs index c769399..9a04f2d 100644 --- a/pasta-tree/src/auth_path/node.rs +++ b/pasta-tree/src/auth_path/node.rs @@ -1,5 +1,5 @@ -use crate::ipa_hiding::HidingIpa; use crate::CycleSideParams; +use crate::ipa_hiding::HidingIpa; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::{PrimeField, Zero}; @@ -24,17 +24,18 @@ impl LevelWitness { } fn x_coords(&self) -> Vec { - self.siblings.iter() - .map(|p| p.x()) - .flatten() - .collect() + self.siblings.iter().map(|p| p.x()).flatten().collect() } pub(crate) fn path_node(&self) -> G { self.siblings[self.path_node_idx] } - pub(crate) fn with_blinding(&self, self_bf: G::ScalarField, parent_bf: G::BaseField) -> LevelWitnessWithBlinding { + pub(crate) fn with_blinding( + &self, + self_bf: G::ScalarField, + parent_bf: G::BaseField, + ) -> LevelWitnessWithBlinding { LevelWitnessWithBlinding { level_witness: self.clone(), bf: self_bf, @@ -42,14 +43,21 @@ impl LevelWitness { } } - pub(crate) fn compute_parent>(&self, params: &CycleSideParams) -> Result + pub(crate) fn compute_parent>( + &self, + params: &CycleSideParams, + ) -> Result where G::BaseField: PrimeField, { self.compute_parent_with_bf(params, C::ScalarField::zero()) } - fn compute_parent_with_bf>(&self, params: &CycleSideParams, bf: C::ScalarField) -> Result + fn compute_parent_with_bf>( + &self, + params: &CycleSideParams, + bf: C::ScalarField, + ) -> Result where G::BaseField: PrimeField, { @@ -57,7 +65,6 @@ impl LevelWitness { } } - /// NB! It is not "blinded", meaning that the blinding factor hasn't been applied. pub struct LevelWitnessWithBlinding { level_witness: LevelWitness, @@ -73,13 +80,23 @@ pub struct LevelWitnessWithBlinding { impl LevelWitnessWithBlinding { pub(crate) fn blinded_path_node(&self, ipa_pcs: &HidingIpa) -> Result { - Ok(ipa_pcs.reblind(self.level_witness.path_node(), G::ScalarField::zero(), self.bf)?.0) + Ok(ipa_pcs + .reblind( + self.level_witness.path_node(), + G::ScalarField::zero(), + self.bf, + )? + .0) } - pub(crate) fn compute_parent>(&self, params: &CycleSideParams) -> Result + pub(crate) fn compute_parent>( + &self, + params: &CycleSideParams, + ) -> Result where G::BaseField: PrimeField, { - self.level_witness.compute_parent_with_bf(params, self.parent_bf) + self.level_witness + .compute_parent_with_bf(params, self.parent_bf) } -} \ No newline at end of file +} diff --git a/pasta-tree/src/auth_path/path.rs b/pasta-tree/src/auth_path/path.rs index 347b429..a8c5256 100644 --- a/pasta-tree/src/auth_path/path.rs +++ b/pasta-tree/src/auth_path/path.rs @@ -1,9 +1,9 @@ +use crate::auth_path::blinded::AuthenticationPathWithBlinding; +use crate::auth_path::node::LevelWitness; +use crate::{CycleParams, CycleSide}; use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_std::rand::Rng; -use crate::auth_path::node::LevelWitness; -use crate::{CycleSide, CycleParams}; -use crate::auth_path::blinded::AuthenticationPathWithBlinding; /// A non-hiding authentication path from a leaf to the root, split between the curves of the cycle. /// For each tree level (excluding the root), the corresponding element of the authentication path (`LevelWitness`) @@ -23,8 +23,8 @@ impl AuthenticationPath where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { fn with_blinding(&self, rng: &mut R) -> AuthenticationPathWithBlinding { let mut path_0 = Vec::with_capacity(self.c0_path.len()); @@ -69,21 +69,33 @@ where self.c0_path[0].path_node() } - fn compute_root(&self, params: &CycleParams) -> Result, ()> { + fn compute_root( + &self, + params: &CycleParams, + ) -> Result, ()> { let mut c0_path_iter = self.c0_path.iter(); let c0_nodes = c0_path_iter.next().unwrap(); // shouldn't be empty - let mut parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + let mut parent_on_c1 = c0_nodes + .compute_parent(¶ms.c1_params) + .unwrap() + .into_affine(); for c1_nodes in self.c1_path.iter() { debug_assert_eq!(parent_on_c1, c1_nodes.path_node()); (parent_on_c1 == c1_nodes.path_node()).ok_or(())?; - let parent_on_c0 = c1_nodes.compute_parent(¶ms.c0_params).unwrap().into_affine(); + let parent_on_c0 = c1_nodes + .compute_parent(¶ms.c0_params) + .unwrap() + .into_affine(); match c0_path_iter.next() { Some(c0_nodes) => { debug_assert_eq!(parent_on_c0, c0_nodes.path_node()); (parent_on_c0 == c0_nodes.path_node()).ok_or(())?; - parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params).unwrap().into_affine(); + parent_on_c1 = c0_nodes + .compute_parent(¶ms.c1_params) + .unwrap() + .into_affine(); } - None => return Ok(CycleSide::C0(parent_on_c0)) + None => return Ok(CycleSide::C0(parent_on_c0)), } } Ok(CycleSide::C1(parent_on_c1)) @@ -92,30 +104,37 @@ where #[cfg(test)] mod tests { + use super::*; use ark_poly::EvaluationDomain; use ark_std::test_rng; use w3f_plonk_common::test_helpers::random_vec; - use super::*; #[test] fn test_auth_path() { let rng = &mut test_rng(); - let params = CycleParams::::setup(9, rng).unwrap(); + let params = + CycleParams::::setup(9, rng).unwrap(); let c0_capacity = params.c0_params.domain.size(); let leaves = random_vec::(c0_capacity, rng); let leaf_index = rng.gen_range(0..c0_capacity); let leaf = leaves[leaf_index]; let leaves = LevelWitness::new(leaves, leaf_index).unwrap(); - let innner_parent = leaves.compute_parent(¶ms.c1_params).unwrap().into_affine(); + let innner_parent = leaves + .compute_parent(¶ms.c1_params) + .unwrap() + .into_affine(); let c1_capacity = params.c1_params.domain.size(); let parent_index = rng.gen_range(0..c1_capacity); let mut inner_nodes = random_vec::(c1_capacity, rng); inner_nodes[parent_index] = innner_parent; let inner_nodes = LevelWitness::new(inner_nodes, parent_index).unwrap(); - let root = inner_nodes.compute_parent(¶ms.c0_params).unwrap().into_affine(); + let root = inner_nodes + .compute_parent(¶ms.c0_params) + .unwrap() + .into_affine(); let path = AuthenticationPath { c0_path: vec![leaves.clone()], @@ -125,13 +144,13 @@ mod tests { assert_eq!(path.get_leaf(), leaf); match path.compute_root(¶ms).unwrap() { CycleSide::C0(root_) => assert_eq!(root_, root), - _ => panic!() + _ => panic!(), } let path_with_bfs = path.with_blinding(rng); match path_with_bfs.compute_root(¶ms).unwrap() { CycleSide::C0(root_) => assert_eq!(root_, root), - _ => panic!() + _ => panic!(), } } -} \ No newline at end of file +} diff --git a/pasta-tree/src/ipa_hiding.rs b/pasta-tree/src/ipa_hiding.rs index 6358277..8a2f4a2 100644 --- a/pasta-tree/src/ipa_hiding.rs +++ b/pasta-tree/src/ipa_hiding.rs @@ -2,13 +2,13 @@ use ark_ec::CurveGroup; use ark_ff::{PrimeField, Zero}; use ark_poly::{DenseUVPolynomial, Polynomial}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use ark_std::rand::Rng; use ark_std::UniformRand; +use ark_std::rand::Rng; +use w3f_pcs::Poly; +use w3f_pcs::pcs::PCS; use w3f_pcs::pcs::ipa::ipa_pc; -use w3f_pcs::pcs::{ipa, CommitterKey, PcsParams, RawVerifierKey, VerifierKey}; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; -use w3f_pcs::pcs::PCS; -use w3f_pcs::Poly; +use w3f_pcs::pcs::{CommitterKey, PcsParams, RawVerifierKey, VerifierKey, ipa}; // To open a hiding commitment `Cp = Commit(p, t1) = (p0.G0 + ... + pn.Gn) + t1.H` at `z`, // the prover: @@ -41,13 +41,18 @@ pub struct HidingProof { a: C::ScalarField, } -impl> HidingIpa { +impl> HidingIpa { pub fn commit_hiding(&self, p: &Poly, t: F) -> Result, ()> { let c = ipa::IPA::commit(&self.ipa_pcs, p)?; self.reblind(c.0, F::zero(), t) } - pub fn reblind(&self, c: C::Affine, r_old: F, r_new: F) -> Result, ()> { + pub fn reblind( + &self, + c: C::Affine, + r_old: F, + r_new: F, + ) -> Result, ()> { let c = c + self.h * (r_new - r_old); let c = c.into_affine(); Ok(WrappedAffine(c)) @@ -98,21 +103,28 @@ impl PCS for HidingIpa { fn setup(max_degree: usize, rng: &mut R) -> Self::Params { let ipa_pcs = ipa::IPA::setup(max_degree, rng); let h = C::Affine::rand(rng); - Self { - ipa_pcs, - h, - } + Self { ipa_pcs, h } } fn commit(ck: &Self::CK, p: &Poly) -> Result { Self::commit_hiding(ck, p, C::ScalarField::zero()) } - fn open(_ck: &Self::CK, _p: &Poly, _x: C::ScalarField) -> Result { + fn open( + _ck: &Self::CK, + _p: &Poly, + _x: C::ScalarField, + ) -> Result { todo!() } - fn open_hiding(ck: &Self::CK, p: &Poly, z: C::ScalarField, t: C::ScalarField, rng: &mut R) -> Result { + fn open_hiding( + ck: &Self::CK, + p: &Poly, + z: C::ScalarField, + t: C::ScalarField, + rng: &mut R, + ) -> Result { let t1 = t; let mut q = Poly::rand(p.degree(), rng); let q_at_z = q.evaluate(&z); @@ -132,20 +144,31 @@ impl PCS for HidingIpa { }) } - fn verify(vk: &Self::VK, c: Self::C, x: C::ScalarField, z: C::ScalarField, proof: Self::Proof) -> Result<(), ()> { + fn verify( + vk: &Self::VK, + c: Self::C, + x: C::ScalarField, + z: C::ScalarField, + proof: Self::Proof, + ) -> Result<(), ()> { let c = c.0 + proof.q * proof.a - vk.h * proof.t; - ipa::IPA::verify(&vk.ipa_pcs, WrappedAffine(c.into_affine()), x, z, proof.ipa_pcs_proof) + ipa::IPA::verify( + &vk.ipa_pcs, + WrappedAffine(c.into_affine()), + x, + z, + proof.ipa_pcs_proof, + ) } } - #[cfg(test)] mod tests { + use crate::ipa_hiding::HidingIpa; use ark_poly::{DenseUVPolynomial, Polynomial}; - use ark_std::{test_rng, UniformRand}; - use w3f_pcs::pcs::PCS; + use ark_std::{UniformRand, test_rng}; use w3f_pcs::Poly; - use crate::ipa_hiding::HidingIpa; + use w3f_pcs::pcs::PCS; #[test] fn test_hiding_ipa_opening() { @@ -163,8 +186,9 @@ mod tests { let z = ark_pallas::Fr::rand(rng); let v = p.evaluate(&z); - let pi = HidingIpa::::open_hiding(&hiding_pcs, &p, z, t, rng).unwrap(); + let pi = + HidingIpa::::open_hiding(&hiding_pcs, &p, z, t, rng).unwrap(); assert!(HidingIpa::::verify(&hiding_pcs, c, z, v, pi).is_ok()); } -} \ No newline at end of file +} diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index 6d5884e..84e9123 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -1,34 +1,39 @@ mod prover; mod verifier; -use crate::ipa_hiding::HidingIpa; use crate::Coeffs; +use crate::ipa_hiding::HidingIpa; use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ec::{CurveGroup, PrimeGroup}; use ark_ff::{PrimeField, Zero}; -use ark_std::rand::Rng; use ark_std::UniformRand; +use ark_std::rand::Rng; use std::marker::PhantomData; -use w3f_pcs::pcs::{PcsParams, PCS}; +use w3f_pcs::pcs::{PCS, PcsParams}; use w3f_pcs::shplonk::AggregateProof; -use w3f_plonk_common::domain::Domain; use w3f_plonk_common::PiopProof; +use w3f_plonk_common::domain::Domain; use w3f_ring_proof::piop::{FixedColumns, RingCommitments, RingEvaluations}; use w3f_ring_proof::{FixedColumnsCommitted, PiopParams, VerifierKey}; -struct CycleSideParams> -{ +struct CycleSideParams> { pcs_params: HidingIpa, - piop_params: PiopParams, + piop_params: PiopParams>, } -struct CycleParams> -{ +struct CycleParams< + C: SWCurveConfig, + G: SWCurveConfig, +> { c0_params: CycleSideParams, G>, c1_params: CycleSideParams, C>, } -impl> CycleParams where C::BaseField: PrimeField { +impl> + CycleParams +where + C::BaseField: PrimeField, +{ pub fn setup(rng: &mut R, domain_size: usize) -> Self { let setup_degree = 3 * domain_size; let pcs_params_0 = HidingIpa::>::setup(setup_degree, rng); @@ -37,26 +42,39 @@ impl::new(domain_size, true); let seed_0 = Affine::::rand(rng); let padding_0 = Affine::::rand(rng); - let piop_params_0 = PiopParams::::setup(domain_0, pcs_params_1.h, seed_0, padding_0); + let piop_params_0 = + PiopParams::>::setup(domain_0, pcs_params_1.h, seed_0, padding_0); let seed_1 = Affine::::rand(rng); let padding_1 = Affine::::rand(rng); - let piop_params_1 = PiopParams::::setup(domain_1, pcs_params_0.h, seed_1, padding_1); + let piop_params_1 = + PiopParams::>::setup(domain_1, pcs_params_0.h, seed_1, padding_1); Self { - c0_params: CycleSideParams { pcs_params: pcs_params_0, piop_params: piop_params_0 }, - c1_params: CycleSideParams { pcs_params: pcs_params_1, piop_params: piop_params_1 }, + c0_params: CycleSideParams { + pcs_params: pcs_params_0, + piop_params: piop_params_0, + }, + c1_params: CycleSideParams { + pcs_params: pcs_params_1, + piop_params: piop_params_1, + }, } } } struct LevelProof { - piop_proof: PiopProof as PCS>::C, RingCommitments as PCS>::C>, RingEvaluations>, + piop_proof: PiopProof< + C::ScalarField, + as PCS>::C, + RingCommitments as PCS>::C>, + RingEvaluations, + >, pcs_opening_proof: AggregateProof>, todo: Coeffs, } type IPACommitment = as PCS<::ScalarField>>::C; -impl> CycleSideParams { +impl> CycleSideParams { pub fn setup(rng: &mut R, domain_size: usize) -> Self { let setup_degree = 3 * domain_size; let pcs_params = HidingIpa::::setup(setup_degree, rng); @@ -71,9 +89,13 @@ impl> CycleSideParams< } } - pub fn commit_child_nodes(&self, nodes: &[Affine], r: C::ScalarField) -> ( + pub fn commit_child_nodes( + &self, + nodes: &[Affine], + r: C::ScalarField, + ) -> ( FixedColumns>, - VerifierKey> + VerifierKey>, ) { let fixed_columns = self.piop_params.fixed_columns(&nodes); let xs = fixed_columns.points.xs.as_poly(); @@ -81,9 +103,17 @@ impl> CycleSideParams< let fixed_columns_committed = FixedColumnsCommitted { points: [ self.pcs_params.commit_hiding(xs, r).unwrap(), - self.pcs_params.commit_hiding(ys, C::ScalarField::zero()).unwrap(), + self.pcs_params + .commit_hiding(ys, C::ScalarField::zero()) + .unwrap(), ], - ring_selector: self.pcs_params.commit_hiding(fixed_columns.ring_selector.as_poly(), C::ScalarField::zero()).unwrap(), + ring_selector: self + .pcs_params + .commit_hiding( + fixed_columns.ring_selector.as_poly(), + C::ScalarField::zero(), + ) + .unwrap(), phantom: PhantomData, }; let verifier_key = VerifierKey { @@ -96,21 +126,24 @@ impl> CycleSideParams< #[cfg(test)] mod tests { - use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; + use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ff::PrimeField; use ark_ff::Zero; use ark_pallas::PallasConfig; use ark_std::rand::Rng; - use ark_std::{end_timer, start_timer, test_rng, UniformRand}; + use ark_std::{UniformRand, end_timer, start_timer, test_rng}; use ark_vesta::VestaConfig; use w3f_plonk_common::test_helpers::random_vec; - use crate::level::{CycleParams, CycleSideParams}; use crate::level::prover::LevelWitness; + use crate::level::{CycleParams, CycleSideParams}; - fn random_node, R: Rng>(params: &CycleSideParams, child: Option>, rng: &mut R) -> (C::Affine, LevelWitness) - { + fn random_node, R: Rng>( + params: &CycleSideParams, + child: Option>, + rng: &mut R, + ) -> (C::Affine, LevelWitness) { let capacity = params.piop_params.keyset_part_size; let mut children = random_vec::, _>(capacity, rng); let i = rng.gen_range(0..capacity); @@ -119,7 +152,9 @@ mod tests { } let fixed_columns = params.piop_params.fixed_columns(&children); let children_xs = fixed_columns.points.xs.as_poly(); - let parent = params.pcs_params.commit_hiding(children_xs, C::ScalarField::zero()); + let parent = params + .pcs_params + .commit_hiding(children_xs, C::ScalarField::zero()); let parent = parent.unwrap().0; let witness = LevelWitness { siblings: children, @@ -134,8 +169,8 @@ mod tests { where F0: PrimeField, F1: PrimeField, - C0: SWCurveConfig, - C1: SWCurveConfig, + C0: SWCurveConfig, + C1: SWCurveConfig, { let rng = &mut test_rng(); @@ -155,7 +190,9 @@ mod tests { let leaf = l2_nodes.siblings[l2_nodes.i]; let capacity = c0_params.piop_params.keyset_part_size; - let t_prove = start_timer!(|| format!("Proving 1st level of a curve tree, domain_size={domain_size}, capacity={capacity}")); + let t_prove = start_timer!(|| format!( + "Proving 1st level of a curve tree, domain_size={domain_size}, capacity={capacity}" + )); let (l1_node_blinded, l1_proof) = c0_params.prove_level(&l1_nodes, rng); end_timer!(t_prove); @@ -164,12 +201,15 @@ mod tests { end_timer!(t_verify); let l2_nodes_parent_r = l1_nodes.child_r; - let (l2_column, l2_vk) = c1_params.commit_child_nodes(l2_nodes.siblings.as_slice(), l2_nodes_parent_r); + let (l2_column, l2_vk) = + c1_params.commit_child_nodes(l2_nodes.siblings.as_slice(), l2_nodes_parent_r); let l1_node_fc = l2_vk.fixed_columns_committed; assert_eq!(l1_node_fc.points[0].0, l1_node_blinded); l2_nodes.parent_r = l2_nodes_parent_r; - let t_prove = start_timer!(|| format!("Proving 2nd level of a curve tree, domain_size={domain_size}, capacity={capacity}")); + let t_prove = start_timer!(|| format!( + "Proving 2nd level of a curve tree, domain_size={domain_size}, capacity={capacity}" + )); let (blinded_leaf, l2_proof) = c1_params.prove_level(&l2_nodes, rng); end_timer!(t_prove); @@ -184,4 +224,4 @@ mod tests { fn test_level_proof() { _test_level_proof::<_, _, PallasConfig, VestaConfig>() } -} \ No newline at end of file +} diff --git a/pasta-tree/src/level/prover.rs b/pasta-tree/src/level/prover.rs index dff2320..af415d3 100644 --- a/pasta-tree/src/level/prover.rs +++ b/pasta-tree/src/level/prover.rs @@ -1,18 +1,18 @@ +use crate::Coeffs; use crate::ipa_hiding::HidingIpa; use crate::level::{CycleSideParams, IPACommitment, LevelProof}; -use crate::Coeffs; -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_poly::Polynomial; use ark_std::rand::Rng; -use ark_std::{end_timer, start_timer, UniformRand}; +use ark_std::{UniformRand, end_timer, start_timer}; use std::collections::BTreeSet; use w3f_pcs::pcs::PcsParams; use w3f_pcs::shplonk::Shplonk; +use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; -use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ArkTranscript; -use ark_poly::Polynomial; -use w3f_plonk_common::piop::ProverPiop; +use w3f_ring_proof::piop::prover::PiopProver; // Witness for the relation (C, C'; i, r, r', x1, ..., xn, yi | C = x1.G1 + ...+ xn.Gn + r'H, C' = (xi, yi) + r.H') pub struct LevelWitness { @@ -23,19 +23,33 @@ pub struct LevelWitness { // TODO: precompute C } -impl> CycleSideParams { +impl> + CycleSideParams +{ // to prove a single level, the prover needs: // 1. witness data: // - parent randomizer // - siblings // - child index // 2. level params - pub fn prove_level(&self, witness: &LevelWitness, rng: &mut R) -> (Affine, LevelProof) { - let (fixed_columns, verifier_key) = self.commit_child_nodes(&witness.siblings, witness.parent_r); + pub fn prove_level( + &self, + witness: &LevelWitness, + rng: &mut R, + ) -> (Affine, LevelProof) { + let (fixed_columns, verifier_key) = + self.commit_child_nodes(&witness.siblings, witness.parent_r); let piop = PiopProver::build(&self.piop_params, fixed_columns, witness.i, witness.child_r); - let blinded_pk = as ProverPiop>>::result(&piop); + let blinded_pk = > as ProverPiop< + C::ScalarField, + IPACommitment, + >>::result(&piop); // let blinded_parent = verifier_key.fixed_columns_committed.points[0].clone(); - let plonk_prover = PlonkProver::, _>::init(self.pcs_params.ck(), verifier_key, ArkTranscript::new(b"pasta-tree-level-proof")); + let plonk_prover = PlonkProver::, _>::init( + self.pcs_params.ck(), + verifier_key, + ArkTranscript::new(b"pasta-tree-level-proof"), + ); let (pcs_openings, piop_proof, mut transcript) = plonk_prover.reduce_to_pcs_opening(piop); let PcsOpeningAt2Points { polys_at_zeta, @@ -46,10 +60,7 @@ impl> = coord_vecs .iter() @@ -79,4 +90,4 @@ impl> CycleSideParams { - pub fn verify_level(&self, parent: FixedColumnsCommitted>, blinded_child: Affine, level_proof: LevelProof) -> bool { +impl> + CycleSideParams +{ + pub fn verify_level( + &self, + parent: FixedColumnsCommitted>, + blinded_child: Affine, + level_proof: LevelProof, + ) -> bool { let verifier_key: VerifierKey> = VerifierKey { pcs_raw_vk: self.pcs_params.raw_vk(), fixed_columns_committed: parent.clone(), }; - let plonk_verifier: PlonkVerifier, _> = PlonkVerifier::init(self.pcs_params.vk(), &verifier_key, ArkTranscript::new(b"pasta-tree-level-proof")); + let plonk_verifier: PlonkVerifier, _> = PlonkVerifier::init( + self.pcs_params.vk(), + &verifier_key, + ArkTranscript::new(b"pasta-tree-level-proof"), + ); let LevelProof { piop_proof, @@ -49,7 +60,7 @@ impl { ipa_pcs: HidingIpa, @@ -37,7 +37,11 @@ impl CycleSideParams { }) } - fn commit_node(&self, children_x_coords: Vec, blinding: C::ScalarField) -> Result { + fn commit_node( + &self, + children_x_coords: Vec, + blinding: C::ScalarField, + ) -> Result { (children_x_coords.len() <= self.domain.size() - self.extra_elements.len()).ok_or(())?; let evals = Evaluations::from_vec_and_domain(children_x_coords, self.domain); let poly = evals.interpolate_by_ref(); @@ -80,10 +84,11 @@ impl> Transcript for Coeffs { #[cfg(test)] mod tests { use super::*; + use ark_ec::AdditiveGroup; use ark_ec::scalar_mul::glv::GLVConfig; use ark_ec::scalar_mul::wnaf::WnafContext; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; - use ark_ec::AdditiveGroup; + use ark_ec::twisted_edwards::TECurveConfig; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; use ark_ff::{BigInteger, Field, Zero}; @@ -92,63 +97,75 @@ mod tests { use ark_poly::Polynomial; use ark_std::iterable::Iterable; use ark_std::rand::Rng; - use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; + use ark_std::{UniformRand, cfg_iter_mut, end_timer, start_timer, test_rng}; use ark_vesta::VestaConfig; use std::collections::BTreeSet; + use w3f_pcs::Poly; + use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::ipa::IPA; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; - use w3f_pcs::pcs::PcsParams; - use w3f_pcs::pcs::{RawVerifierKey, PCS}; + use w3f_pcs::pcs::{PCS, RawVerifierKey}; use w3f_pcs::shplonk::Shplonk; - use w3f_pcs::Poly; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::PlonkProver; use w3f_plonk_common::test_helpers::random_vec; use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ring_prover::RingProver; use w3f_ring_proof::ring_verifier::RingVerifier; - use w3f_ring_proof::{index, test_setup, ArkTranscript}; + use w3f_ring_proof::{ArkTranscript, PiopParams, index}; #[cfg(feature = "parallel")] use rayon::prelude::*; + use w3f_plonk_common::domain::Domain; type PallasIPA = IPA; type PallasC = WrappedAffine; - // cargo test test_pasta_ring_plonk --release --features="print-trace" -- --show-output - #[test] - fn test_pasta_ring_plonk() { - let rng = &mut test_rng(); - - // setup - let domain_size = 2usize.pow(9); - let (pcs_params, piop_params) = - test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); - let keyset_size = piop_params.keyset_part_size; - let pks = random_vec::(keyset_size, rng); - let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); - let blinding = ark_vesta::Fr::rand(rng); - let pk_idx = rng.gen_range(0..keyset_size); - let blinded_pk = piop_params.blind_pk(pks[pk_idx], blinding); - - // prover - let fs = ArkTranscript::new(b"pasta-ring-proof-test"); - let prover = RingProver::init(prover_key, piop_params.clone(), 0, fs.clone()); - let t_prove = start_timer!(|| format!( - "Proving IPA ring-proof with plonk, domain_size={domain_size}, keyset_size={keyset_size}" - )); - let (blinded_pk_, proof) = prover.rerandomize_pk(pk_idx, blinding); - end_timer!(t_prove); - assert_eq!(blinded_pk_, blinded_pk); - - // verifier - let ring_verifier = RingVerifier::init(verifier_key, piop_params, fs); - let t_verify = start_timer!(|| "Verifying IPA plonk opening"); - let valid = ring_verifier.verify(proof, blinded_pk); - end_timer!(t_verify); - assert!(valid); + fn setup, G: AffineRepr>( + rng: &mut R, + domain_size: usize, + ) -> (CS::Params, PiopParams) { + let setup_degree = 3 * domain_size; + let pcs_params = CS::setup(setup_degree, rng); + let domain = Domain::new(domain_size, true); + let piop_params = PiopParams::setup(domain, G::rand(rng), G::rand(rng), G::rand(rng)); + (pcs_params, piop_params) } + // // cargo test test_pasta_ring_plonk --release --features="print-trace" -- --show-output + // #[test] + // fn test_pasta_ring_plonk() { + // let rng = &mut test_rng(); + // + // // setup + // let domain_size = 2usize.pow(9); + // let (pcs_params, piop_params) = + // setup::<_, PallasIPA, ark_vesta::Affine>(rng, domain_size); + // let keyset_size = piop_params.keyset_part_size; + // let pks = random_vec::(keyset_size, rng); + // let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); + // let blinding = ark_vesta::Fr::rand(rng); + // let pk_idx = rng.gen_range(0..keyset_size); + // let blinded_pk = piop_params.blind_pk(pks[pk_idx], blinding); + // + // // prover + // let fs = ArkTranscript::new(b"pasta-ring-proof-test"); + // let prover = RingProver::init(prover_key, piop_params.clone(), 0, fs.clone()); + // let t_prove = start_timer!(|| format!( + // "Proving IPA ring-proof with plonk, domain_size={domain_size}, keyset_size={keyset_size}" + // )); + // let (blinded_pk_, proof) = prover.rerandomize_pk(pk_idx, blinding); + // end_timer!(t_prove); + // assert_eq!(blinded_pk_, blinded_pk); + // + // // verifier + // let ring_verifier = RingVerifier::init(verifier_key, piop_params, fs); + // let t_verify = start_timer!(|| "Verifying IPA plonk opening"); + // let valid = ring_verifier.verify(proof, blinded_pk); + // end_timer!(t_verify); + // assert!(valid); + // } + // cargo test test_pasta_ring_shplonk --release --features="print-trace" -- --show-output #[test] fn test_pasta_ring_shplonk() { @@ -156,8 +173,7 @@ mod tests { // setup let domain_size = 2usize.pow(9); - let (pcs_params, piop_params) = - test_setup::<_, _, PallasIPA, VestaConfig>(rng, domain_size); + let (pcs_params, piop_params) = setup::<_, PallasIPA, ark_vesta::Affine>(rng, domain_size); let keyset_size = piop_params.keyset_part_size; let pks = random_vec::(keyset_size, rng); let (prover_key, verifier_key) = index::<_, PallasIPA, _>(&pcs_params, &piop_params, &pks); @@ -172,7 +188,7 @@ mod tests { let pcs_vk = verifier_key.pcs_raw_vk.prepare(); // prover - let piop = PiopProver::::build( + let piop = PiopProver::::build( &piop_params, prover_key.fixed_columns.clone(), pk_idx, @@ -194,7 +210,7 @@ mod tests { &constraints, &alphas, ) - .interpolate(); + .interpolate(); let quotient = piop_params .domain .divide_by_vanishing_poly(&agg_constraint_poly); diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 0fa42c0..4b16b4d 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -1,10 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] - -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ff::PrimeField; use ark_serialize::CanonicalSerialize; -use ark_std::rand::{Rng, RngCore}; -use ark_std::UniformRand; +use ark_std::rand::RngCore; use w3f_pcs::pcs::PCS; pub use piop::index; @@ -51,20 +48,6 @@ impl ArkTranscript { } } -pub fn test_setup, G: TECurveConfig>( - rng: &mut R, - domain_size: usize, -) -> (CS::Params, PiopParams>) { - let setup_degree = 3 * domain_size; - let pcs_params = CS::setup(setup_degree, rng); - let domain = Domain::new(domain_size, true); - let h = Affine::::rand(rng); - let seed = Affine::::rand(rng); - let padding = Affine::::rand(rng); - let piop_params = PiopParams::setup(domain, h, seed, padding); - (pcs_params, piop_params) -} - #[cfg(test)] mod tests { use ark_bls12_381::Bls12_381; From 3559863651bee73059dba3d28fbc1a07adb0fb10 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 16:02:35 +0300 Subject: [PATCH 23/36] code cleaned up --- pasta-tree/src/auth_path/blinded.rs | 29 ++-- pasta-tree/src/auth_path/node.rs | 46 ++++--- pasta-tree/src/auth_path/path.rs | 34 ++--- pasta-tree/src/level/mod.rs | 183 ++++++------------------- pasta-tree/src/level/prover.rs | 42 +++--- pasta-tree/src/level/verifier.rs | 10 +- pasta-tree/src/lib.rs | 200 ++++++++++++++++++++-------- w3f-plonk-common/src/domain.rs | 8 +- 8 files changed, 263 insertions(+), 289 deletions(-) diff --git a/pasta-tree/src/auth_path/blinded.rs b/pasta-tree/src/auth_path/blinded.rs index 95fec84..47a82fd 100644 --- a/pasta-tree/src/auth_path/blinded.rs +++ b/pasta-tree/src/auth_path/blinded.rs @@ -12,37 +12,28 @@ impl AuthenticationPathWithBlinding where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { pub(crate) fn compute_root( &self, params: &CycleParams, ) -> Result, ()> { - let mut path_0_iter = self.c0_path.iter(); - let c0_nodes = path_0_iter.next().unwrap(); - let mut parent_on_c1 = c0_nodes - .compute_parent(¶ms.c1_params) - .unwrap() - .into_affine(); + let mut c0_path_iter = self.c0_path.iter(); + let c0_nodes = c0_path_iter.next().unwrap(); + let mut parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params)?; for c1_nodes in self.c1_path.iter() { - let next_c1_path_node = c1_nodes.blinded_path_node(¶ms.c1_params.ipa_pcs)?; + let next_c1_path_node = c1_nodes.blinded_path_node(¶ms.c1_params.pcs_params)?; debug_assert_eq!(parent_on_c1, next_c1_path_node); (parent_on_c1 == next_c1_path_node).ok_or(())?; - let parent_on_c0 = c1_nodes - .compute_parent(¶ms.c0_params) - .unwrap() - .into_affine(); - match path_0_iter.next() { + let parent_on_c0 = c1_nodes.compute_parent(¶ms.c0_params)?; + match c0_path_iter.next() { Some(c0_nodes) => { let next_c0_path_node = - c0_nodes.blinded_path_node(¶ms.c0_params.ipa_pcs)?; + c0_nodes.blinded_path_node(¶ms.c0_params.pcs_params)?; debug_assert_eq!(parent_on_c0, next_c0_path_node); (parent_on_c0 == next_c0_path_node).ok_or(())?; - parent_on_c1 = c0_nodes - .compute_parent(¶ms.c1_params) - .unwrap() - .into_affine(); + parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params)?; } None => return Ok(CycleSide::C0(parent_on_c0)), } diff --git a/pasta-tree/src/auth_path/node.rs b/pasta-tree/src/auth_path/node.rs index 9a04f2d..95ef451 100644 --- a/pasta-tree/src/auth_path/node.rs +++ b/pasta-tree/src/auth_path/node.rs @@ -2,6 +2,8 @@ use crate::CycleSideParams; use crate::ipa_hiding::HidingIpa; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::{PrimeField, Zero}; +use ark_std::rand::Rng; +use ark_std::UniformRand; /// An element of a tree authentication path. A node on the path together with it's sibling. /// `path_node = self.siblings[self.path_node_idx]` is the node on the path. @@ -9,8 +11,8 @@ use ark_ff::{PrimeField, Zero}; // TODO: the minimal witness is x-coords of the siblings, and y_i #[derive(Clone, Debug)] pub struct LevelWitness { - siblings: Vec, - path_node_idx: usize, + pub(crate) siblings: Vec, + pub(crate) path_node_idx: usize, } impl LevelWitness { @@ -43,10 +45,18 @@ impl LevelWitness { } } + pub(crate) fn with_random_blinding( + &self, + parent_bf: G::BaseField, + rng: &mut R, + ) -> LevelWitnessWithBlinding { + self.with_blinding(G::ScalarField::rand(rng), parent_bf) + } + pub(crate) fn compute_parent>( &self, - params: &CycleSideParams, - ) -> Result + params: &CycleSideParams, + ) -> Result where G::BaseField: PrimeField, { @@ -55,48 +65,42 @@ impl LevelWitness { fn compute_parent_with_bf>( &self, - params: &CycleSideParams, + params: &CycleSideParams, bf: C::ScalarField, - ) -> Result + ) -> Result where G::BaseField: PrimeField, { - params.commit_node(self.x_coords(), bf) + params.commit_nodes(&self.siblings, bf) } } /// NB! It is not "blinded", meaning that the blinding factor hasn't been applied. pub struct LevelWitnessWithBlinding { - level_witness: LevelWitness, + pub(crate) level_witness: LevelWitness, /// the verifier gets `Ci' = siblings[i] + bf.H` - bf: G::ScalarField, + pub(crate) bf: G::ScalarField, /// Let `Ci = c1.G1 + ... + cm.Gm` -- the non-hiding commitment to a level. /// Provided that, instead, the verifier gets `Ci' = Ci + bf.H`, /// when opening the commitment, the prover interprets it as a hiding commitment /// and needs to know the parent's blinding factor to open to the same values. /// The root is not blinded, so `parent_bf = 0` for the level below the root. - parent_bf: G::BaseField, // = C::ScalarField + pub(crate) parent_bf: G::BaseField, // = C::ScalarField } impl LevelWitnessWithBlinding { pub(crate) fn blinded_path_node(&self, ipa_pcs: &HidingIpa) -> Result { - Ok(ipa_pcs - .reblind( - self.level_witness.path_node(), - G::ScalarField::zero(), - self.bf, - )? - .0) + let blinded_path_node = ipa_pcs.reblind(self.level_witness.path_node(), G::ScalarField::zero(), self.bf)?; + Ok(blinded_path_node.0) } pub(crate) fn compute_parent>( &self, - params: &CycleSideParams, - ) -> Result + params: &CycleSideParams, + ) -> Result where G::BaseField: PrimeField, { - self.level_witness - .compute_parent_with_bf(params, self.parent_bf) + self.level_witness.compute_parent_with_bf(params, self.parent_bf) } } diff --git a/pasta-tree/src/auth_path/path.rs b/pasta-tree/src/auth_path/path.rs index a8c5256..ec6ea05 100644 --- a/pasta-tree/src/auth_path/path.rs +++ b/pasta-tree/src/auth_path/path.rs @@ -75,25 +75,16 @@ where ) -> Result, ()> { let mut c0_path_iter = self.c0_path.iter(); let c0_nodes = c0_path_iter.next().unwrap(); // shouldn't be empty - let mut parent_on_c1 = c0_nodes - .compute_parent(¶ms.c1_params) - .unwrap() - .into_affine(); + let mut parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params)?; for c1_nodes in self.c1_path.iter() { debug_assert_eq!(parent_on_c1, c1_nodes.path_node()); (parent_on_c1 == c1_nodes.path_node()).ok_or(())?; - let parent_on_c0 = c1_nodes - .compute_parent(¶ms.c0_params) - .unwrap() - .into_affine(); + let parent_on_c0 = c1_nodes.compute_parent(¶ms.c0_params)?; match c0_path_iter.next() { Some(c0_nodes) => { debug_assert_eq!(parent_on_c0, c0_nodes.path_node()); (parent_on_c0 == c0_nodes.path_node()).ok_or(())?; - parent_on_c1 = c0_nodes - .compute_parent(¶ms.c1_params) - .unwrap() - .into_affine(); + parent_on_c1 = c0_nodes .compute_parent(¶ms.c1_params)?; } None => return Ok(CycleSide::C0(parent_on_c0)), } @@ -105,7 +96,6 @@ where #[cfg(test)] mod tests { use super::*; - use ark_poly::EvaluationDomain; use ark_std::test_rng; use w3f_plonk_common::test_helpers::random_vec; @@ -113,28 +103,22 @@ mod tests { fn test_auth_path() { let rng = &mut test_rng(); - let params = - CycleParams::::setup(9, rng).unwrap(); + let domain_size = 2usize.pow(9); + let params = CycleParams::::setup(domain_size, rng); - let c0_capacity = params.c0_params.domain.size(); + let c0_capacity = params.c0_params.piop_params.keyset_part_size; let leaves = random_vec::(c0_capacity, rng); let leaf_index = rng.gen_range(0..c0_capacity); let leaf = leaves[leaf_index]; let leaves = LevelWitness::new(leaves, leaf_index).unwrap(); - let innner_parent = leaves - .compute_parent(¶ms.c1_params) - .unwrap() - .into_affine(); + let innner_parent = leaves.compute_parent(¶ms.c1_params).unwrap(); - let c1_capacity = params.c1_params.domain.size(); + let c1_capacity = params.c1_params.piop_params.keyset_part_size; let parent_index = rng.gen_range(0..c1_capacity); let mut inner_nodes = random_vec::(c1_capacity, rng); inner_nodes[parent_index] = innner_parent; let inner_nodes = LevelWitness::new(inner_nodes, parent_index).unwrap(); - let root = inner_nodes - .compute_parent(¶ms.c0_params) - .unwrap() - .into_affine(); + let root = inner_nodes.compute_parent(¶ms.c0_params).unwrap(); let path = AuthenticationPath { c0_path: vec![leaves.clone()], diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index 84e9123..6e32ebc 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -1,67 +1,16 @@ mod prover; mod verifier; -use crate::Coeffs; use crate::ipa_hiding::HidingIpa; -use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; +use crate::Coeffs; use ark_ec::{CurveGroup, PrimeGroup}; -use ark_ff::{PrimeField, Zero}; -use ark_std::UniformRand; -use ark_std::rand::Rng; -use std::marker::PhantomData; -use w3f_pcs::pcs::{PCS, PcsParams}; +use w3f_pcs::pcs::PCS; use w3f_pcs::shplonk::AggregateProof; use w3f_plonk_common::PiopProof; -use w3f_plonk_common::domain::Domain; -use w3f_ring_proof::piop::{FixedColumns, RingCommitments, RingEvaluations}; -use w3f_ring_proof::{FixedColumnsCommitted, PiopParams, VerifierKey}; - -struct CycleSideParams> { - pcs_params: HidingIpa, - piop_params: PiopParams>, -} - -struct CycleParams< - C: SWCurveConfig, - G: SWCurveConfig, -> { - c0_params: CycleSideParams, G>, - c1_params: CycleSideParams, C>, -} +use w3f_ring_proof::piop::{RingCommitments, RingEvaluations}; -impl> - CycleParams -where - C::BaseField: PrimeField, -{ - pub fn setup(rng: &mut R, domain_size: usize) -> Self { - let setup_degree = 3 * domain_size; - let pcs_params_0 = HidingIpa::>::setup(setup_degree, rng); - let pcs_params_1 = HidingIpa::>::setup(setup_degree, rng); - let domain_0 = Domain::::new(domain_size, true); - let domain_1 = Domain::::new(domain_size, true); - let seed_0 = Affine::::rand(rng); - let padding_0 = Affine::::rand(rng); - let piop_params_0 = - PiopParams::>::setup(domain_0, pcs_params_1.h, seed_0, padding_0); - let seed_1 = Affine::::rand(rng); - let padding_1 = Affine::::rand(rng); - let piop_params_1 = - PiopParams::>::setup(domain_1, pcs_params_0.h, seed_1, padding_1); - Self { - c0_params: CycleSideParams { - pcs_params: pcs_params_0, - piop_params: piop_params_0, - }, - c1_params: CycleSideParams { - pcs_params: pcs_params_1, - piop_params: piop_params_1, - }, - } - } -} -struct LevelProof { +pub struct LevelProof { piop_proof: PiopProof< C::ScalarField, as PCS>::C, @@ -74,95 +23,44 @@ struct LevelProof { type IPACommitment = as PCS<::ScalarField>>::C; -impl> CycleSideParams { - pub fn setup(rng: &mut R, domain_size: usize) -> Self { - let setup_degree = 3 * domain_size; - let pcs_params = HidingIpa::::setup(setup_degree, rng); - let domain = Domain::new(domain_size, true); - let h = Affine::::rand(rng); - let seed = Affine::::rand(rng); - let padding = Affine::::rand(rng); - let piop_params = PiopParams::setup(domain, h, seed, padding); - Self { - pcs_params, - piop_params, - } - } - - pub fn commit_child_nodes( - &self, - nodes: &[Affine], - r: C::ScalarField, - ) -> ( - FixedColumns>, - VerifierKey>, - ) { - let fixed_columns = self.piop_params.fixed_columns(&nodes); - let xs = fixed_columns.points.xs.as_poly(); - let ys = fixed_columns.points.ys.as_poly(); - let fixed_columns_committed = FixedColumnsCommitted { - points: [ - self.pcs_params.commit_hiding(xs, r).unwrap(), - self.pcs_params - .commit_hiding(ys, C::ScalarField::zero()) - .unwrap(), - ], - ring_selector: self - .pcs_params - .commit_hiding( - fixed_columns.ring_selector.as_poly(), - C::ScalarField::zero(), - ) - .unwrap(), - phantom: PhantomData, - }; - let verifier_key = VerifierKey { - pcs_raw_vk: self.pcs_params.raw_vk(), - fixed_columns_committed, - }; - (fixed_columns, verifier_key) - } -} #[cfg(test)] mod tests { - use ark_ec::CurveGroup; - use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; + use crate::auth_path::node::LevelWitness; + use crate::CycleParams; + use crate::CycleSideParams; + use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; + use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; - use ark_ff::Zero; use ark_pallas::PallasConfig; use ark_std::rand::Rng; - use ark_std::{UniformRand, end_timer, start_timer, test_rng}; + use ark_std::{end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; use w3f_plonk_common::test_helpers::random_vec; - use crate::level::prover::LevelWitness; - use crate::level::{CycleParams, CycleSideParams}; - - fn random_node, R: Rng>( + fn random_witness, R: Rng>( params: &CycleSideParams, - child: Option>, + path_node: G, rng: &mut R, - ) -> (C::Affine, LevelWitness) { + ) -> LevelWitness { let capacity = params.piop_params.keyset_part_size; - let mut children = random_vec::, _>(capacity, rng); + let mut nodes = random_vec::(capacity, rng); let i = rng.gen_range(0..capacity); - if child.is_some() { - children[i] = child.unwrap(); + nodes[i] = path_node; + LevelWitness { + siblings: nodes, + path_node_idx: i, } - let fixed_columns = params.piop_params.fixed_columns(&children); - let children_xs = fixed_columns.points.xs.as_poly(); - let parent = params - .pcs_params - .commit_hiding(children_xs, C::ScalarField::zero()); - let parent = parent.unwrap().0; - let witness = LevelWitness { - siblings: children, - i, - child_r: G::ScalarField::rand(rng), - parent_r: C::ScalarField::zero(), - }; - (parent, witness) + } + + fn random_node, R: Rng>( + params: &CycleSideParams, + path_node: G, + rng: &mut R, + ) -> (C::Affine, LevelWitness) { + let level_witness = random_witness(params, path_node, rng); + let parent = level_witness.compute_parent(params).unwrap(); + (parent, level_witness) } fn _test_level_proof() @@ -174,43 +72,42 @@ mod tests { { let rng = &mut test_rng(); - // setup let domain_size = 2usize.pow(9); let CycleParams { c0_params, c1_params, - } = CycleParams::::setup(rng, domain_size); + } = CycleParams::, Projective>::setup(domain_size, rng); - let (l1_node, mut l2_nodes) = random_node(&c1_params, None, rng); - let (l0_node, l1_nodes) = random_node(&c0_params, Some(l1_node), rng); - - let (_, l1_vk) = c0_params.commit_child_nodes(l1_nodes.siblings.as_slice(), F0::zero()); + let leaf = Affine::::rand(rng); + let (l1_node, mut l2_nodes) = random_node(&c1_params, leaf, rng); + let (root, l1_nodes) = random_node(&c0_params, l1_node, rng); + let (_, l1_vk) = c0_params.commit_children(l1_nodes.siblings.as_slice(), F0::zero()); let root_fc = l1_vk.fixed_columns_committed; - let leaf = l2_nodes.siblings[l2_nodes.i]; let capacity = c0_params.piop_params.keyset_part_size; + let l1_nodes_with_bf = l1_nodes.with_random_blinding(F0::zero(), rng); let t_prove = start_timer!(|| format!( "Proving 1st level of a curve tree, domain_size={domain_size}, capacity={capacity}" )); - let (l1_node_blinded, l1_proof) = c0_params.prove_level(&l1_nodes, rng); + let (l1_node_blinded, l1_proof) = c0_params.prove_level(&l1_nodes_with_bf, rng); end_timer!(t_prove); let t_verify = start_timer!(|| format!("Verifying a single-level proof")); assert!(c0_params.verify_level(root_fc, l1_node_blinded, l1_proof)); end_timer!(t_verify); - let l2_nodes_parent_r = l1_nodes.child_r; - let (l2_column, l2_vk) = - c1_params.commit_child_nodes(l2_nodes.siblings.as_slice(), l2_nodes_parent_r); + let capacity = c1_params.piop_params.keyset_part_size; + + let (_, l2_vk) = c1_params.commit_children(l2_nodes.siblings.as_slice(), l1_nodes_with_bf.bf); let l1_node_fc = l2_vk.fixed_columns_committed; assert_eq!(l1_node_fc.points[0].0, l1_node_blinded); - l2_nodes.parent_r = l2_nodes_parent_r; + let l2_nodes_with_bf = l2_nodes.with_random_blinding(l1_nodes_with_bf.bf, rng); let t_prove = start_timer!(|| format!( "Proving 2nd level of a curve tree, domain_size={domain_size}, capacity={capacity}" )); - let (blinded_leaf, l2_proof) = c1_params.prove_level(&l2_nodes, rng); + let (blinded_leaf, l2_proof) = c1_params.prove_level(&l2_nodes_with_bf, rng); end_timer!(t_prove); let t_verify = start_timer!(|| format!("Verifying a single-level proof")); diff --git a/pasta-tree/src/level/prover.rs b/pasta-tree/src/level/prover.rs index af415d3..239d43c 100644 --- a/pasta-tree/src/level/prover.rs +++ b/pasta-tree/src/level/prover.rs @@ -1,30 +1,30 @@ -use crate::Coeffs; +use crate::auth_path::node::LevelWitnessWithBlinding; use crate::ipa_hiding::HidingIpa; -use crate::level::{CycleSideParams, IPACommitment, LevelProof}; -use ark_ec::CurveGroup; +use crate::level::{IPACommitment, LevelProof}; +use crate::{Coeffs, CycleSideParams}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::CurveGroup; use ark_poly::Polynomial; use ark_std::rand::Rng; -use ark_std::{UniformRand, end_timer, start_timer}; +use ark_std::{end_timer, start_timer, UniformRand}; use std::collections::BTreeSet; use w3f_pcs::pcs::PcsParams; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; -use w3f_ring_proof::ArkTranscript; use w3f_ring_proof::piop::prover::PiopProver; - -// Witness for the relation (C, C'; i, r, r', x1, ..., xn, yi | C = x1.G1 + ...+ xn.Gn + r'H, C' = (xi, yi) + r.H') -pub struct LevelWitness { - pub siblings: Vec>, - pub i: usize, - pub child_r: G::ScalarField, - pub parent_r: G::BaseField, - // TODO: precompute C -} +use w3f_ring_proof::ArkTranscript; +// // Witness for the relation (C, C'; i, r, r', x1, ..., xn, yi | C = x1.G1 + ...+ xn.Gn + r'H, C' = (xi, yi) + r.H') +// pub struct LevelWitness { +// pub siblings: Vec>, +// pub i: usize, +// pub child_r: G::ScalarField, +// pub parent_r: G::BaseField, +// // TODO: precompute C +// } impl> - CycleSideParams + CycleSideParams> { // to prove a single level, the prover needs: // 1. witness data: @@ -34,13 +34,13 @@ impl( &self, - witness: &LevelWitness, + witness: &LevelWitnessWithBlinding>, rng: &mut R, ) -> (Affine, LevelProof) { let (fixed_columns, verifier_key) = - self.commit_child_nodes(&witness.siblings, witness.parent_r); - let piop = PiopProver::build(&self.piop_params, fixed_columns, witness.i, witness.child_r); - let blinded_pk = > as ProverPiop< + self.commit_children(&witness.level_witness.siblings, witness.parent_bf); + let piop = PiopProver::build(&self.piop_params, fixed_columns, witness.level_witness.path_node_idx, witness.bf); + let blinded_node = > as ProverPiop< C::ScalarField, IPACommitment, >>::result(&piop); @@ -78,7 +78,7 @@ impl> - CycleSideParams + +impl> +CycleSideParams> { pub fn verify_level( &self, diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 3d090cd..f88007e 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,67 +1,167 @@ #![feature(bool_to_result)] use crate::ipa_hiding::HidingIpa; -use ark_ec::CurveGroup; -use ark_ff::PrimeField; -use ark_poly::{EvaluationDomain, Evaluations, Radix2EvaluationDomain}; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_ff::{PrimeField, Zero}; use ark_std::rand::Rng; +use std::marker::PhantomData; use w3f_pcs::aggregation::multiple::Transcript; +use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::PCS; +use w3f_plonk_common::domain::Domain; +use w3f_ring_proof::piop::FixedColumns; +use w3f_ring_proof::{FixedColumnsCommitted, PiopParams, VerifierKey}; + mod auth_path; pub mod ipa_hiding; pub mod level; -pub struct CycleSideParams { - ipa_pcs: HidingIpa, - domain: Radix2EvaluationDomain, - extra_elements: Vec, - extra_commitment: C, +struct CycleSideParams> { + pcs_params: HidingIpa, + piop_params: PiopParams, } -pub struct CycleParams { - c0_params: CycleSideParams, - c1_params: CycleSideParams, +struct CycleParams< + C0: CurveGroup, + C1: CurveGroup, +> { + c0_params: CycleSideParams, + c1_params: CycleSideParams, } -impl CycleSideParams { - fn setup(log_n: u32, rng: &mut R) -> Result { - let n = 2usize.pow(log_n); - let domain = Radix2EvaluationDomain::new(n).ok_or(())?; - let ipa_pcs = HidingIpa::setup(n - 1, rng); - Ok(Self { - ipa_pcs, - domain, - extra_elements: vec![], - extra_commitment: C::zero(), - }) +impl CycleParams +where + F0: PrimeField, + F1: PrimeField, + C0: CurveGroup, + C1: CurveGroup, +{ + pub fn setup(domain_size: usize, rng: &mut R) -> Self { + let setup_degree = 3 * domain_size; + let c0_pcs_params = HidingIpa::::setup(setup_degree, rng); + let c1_pcs_params = HidingIpa::::setup(setup_degree, rng); + let c0_piop_params = piop_params(domain_size, c1_pcs_params.h, rng); + let c1_piop_params = piop_params(domain_size, c0_pcs_params.h, rng); + Self { + c0_params: CycleSideParams { + pcs_params: c0_pcs_params, + piop_params: c0_piop_params, + }, + c1_params: CycleSideParams { + pcs_params: c1_pcs_params, + piop_params: c1_piop_params, + }, + } } +} + +fn piop_params, R: Rng>(domain_size: usize, h: G, rng: &mut R) -> PiopParams { + let domain = Domain::::new(domain_size, true); + let seed = G::rand(rng); + let padding = G::rand(rng); + PiopParams::setup(domain, h, seed, padding) +} + +impl> CycleSideParams { - fn commit_node( + pub fn commit_children( &self, - children_x_coords: Vec, - blinding: C::ScalarField, - ) -> Result { - (children_x_coords.len() <= self.domain.size() - self.extra_elements.len()).ok_or(())?; - let evals = Evaluations::from_vec_and_domain(children_x_coords, self.domain); - let poly = evals.interpolate_by_ref(); - let x_coords_committed = self.ipa_pcs.commit_hiding(&poly, blinding)?.0; - let node_committed = x_coords_committed + self.extra_commitment; - Ok(node_committed) + children: &[G], + bf: C::ScalarField, + ) -> ( + FixedColumns, + VerifierKey>, + ) { + let fixed_columns = self.piop_params.fixed_columns(&children); + let xs = fixed_columns.points.xs.as_poly(); + let ys = fixed_columns.points.ys.as_poly(); + let fixed_columns_committed = FixedColumnsCommitted { + points: [ + self.pcs_params.commit_hiding(xs, bf).unwrap(), + self.pcs_params + .commit_hiding(ys, C::ScalarField::zero()) + .unwrap(), + ], + ring_selector: self + .pcs_params + .commit_hiding( + fixed_columns.ring_selector.as_poly(), + C::ScalarField::zero(), + ) + .unwrap(), + phantom: PhantomData, + }; + let verifier_key = VerifierKey { + pcs_raw_vk: self.pcs_params.raw_vk(), + fixed_columns_committed, + }; + (fixed_columns, verifier_key) } -} -impl CycleParams { - fn setup(log_n: u32, rng: &mut R) -> Result { - let c0_params = CycleSideParams::setup(log_n, rng)?; - let c1_params = CycleSideParams::setup(log_n, rng)?; - Ok(Self { - c0_params, - c1_params, - }) + fn commit_nodes( + &self, + nodes: &[G], + // children_x_coords: Vec, + blinding: C::ScalarField, + ) -> Result { + let xs = self.piop_params.points_column(nodes).xs; + Ok(self.pcs_params.commit_hiding(xs.as_poly(), blinding)?.0) } } + +// pub struct CycleSideParams { +// ipa_pcs: HidingIpa, +// domain: Radix2EvaluationDomain, +// extra_elements: Vec, +// extra_commitment: C, +// } + +// pub struct CycleParams { +// c0_params: CycleSideParams, +// c1_params: CycleSideParams, +// } + + +// impl CycleSideParams { +// fn setup(log_n: u32, rng: &mut R) -> Result { +// let n = 2usize.pow(log_n); +// let domain = Radix2EvaluationDomain::new(n).ok_or(())?; +// let ipa_pcs = HidingIpa::setup(n - 1, rng); +// Ok(Self { +// ipa_pcs, +// domain, +// extra_elements: vec![], +// extra_commitment: C::zero(), +// }) +// } +// +// fn commit_node( +// &self, +// children_x_coords: Vec, +// blinding: C::ScalarField, +// ) -> Result { +// (children_x_coords.len() <= self.domain.size() - self.extra_elements.len()).ok_or(())?; +// let evals = Evaluations::from_vec_and_domain(children_x_coords, self.domain); +// let poly = evals.interpolate_by_ref(); +// let x_coords_committed = self.ipa_pcs.commit_hiding(&poly, blinding)?.0; +// let node_committed = x_coords_committed + self.extra_commitment; +// Ok(node_committed) +// } +// } + +// impl CycleParams { +// fn setup(log_n: u32, rng: &mut R) -> Result { +// let c0_params = CycleSideParams::setup(log_n, rng)?; +// let c1_params = CycleSideParams::setup(log_n, rng)?; +// Ok(Self { +// c0_params, +// c1_params, +// }) +// } +// } + enum CycleSide { C0(C0), C1(C1), @@ -84,11 +184,10 @@ impl> Transcript for Coeffs { #[cfg(test)] mod tests { use super::*; - use ark_ec::AdditiveGroup; use ark_ec::scalar_mul::glv::GLVConfig; use ark_ec::scalar_mul::wnaf::WnafContext; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; - use ark_ec::twisted_edwards::TECurveConfig; + use ark_ec::AdditiveGroup; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; use ark_ff::{BigInteger, Field, Zero}; @@ -97,22 +196,19 @@ mod tests { use ark_poly::Polynomial; use ark_std::iterable::Iterable; use ark_std::rand::Rng; - use ark_std::{UniformRand, cfg_iter_mut, end_timer, start_timer, test_rng}; - use ark_vesta::VestaConfig; + use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; use std::collections::BTreeSet; - use w3f_pcs::Poly; - use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::ipa::IPA; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; - use w3f_pcs::pcs::{PCS, RawVerifierKey}; + use w3f_pcs::pcs::PcsParams; + use w3f_pcs::pcs::{RawVerifierKey, PCS}; use w3f_pcs::shplonk::Shplonk; + use w3f_pcs::Poly; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::PlonkProver; use w3f_plonk_common::test_helpers::random_vec; use w3f_ring_proof::piop::prover::PiopProver; - use w3f_ring_proof::ring_prover::RingProver; - use w3f_ring_proof::ring_verifier::RingVerifier; - use w3f_ring_proof::{ArkTranscript, PiopParams, index}; + use w3f_ring_proof::{index, ArkTranscript, PiopParams}; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -210,7 +306,7 @@ mod tests { &constraints, &alphas, ) - .interpolate(); + .interpolate(); let quotient = piop_params .domain .divide_by_vanishing_poly(&agg_constraint_poly); diff --git a/w3f-plonk-common/src/domain.rs b/w3f-plonk-common/src/domain.rs index b4392e0..34e0eb1 100644 --- a/w3f-plonk-common/src/domain.rs +++ b/w3f-plonk-common/src/domain.rs @@ -11,9 +11,9 @@ pub const ZK_ROWS: usize = 3; // Domains for performing calculations with constraint polynomials of degree up to 4. #[derive(Clone)] -struct Domains { - x1: GeneralEvaluationDomain, - x4: GeneralEvaluationDomain, +pub struct Domains { + pub x1: GeneralEvaluationDomain, + pub x4: GeneralEvaluationDomain, } impl Domains { @@ -59,7 +59,7 @@ impl Domains { #[derive(Clone)] pub struct Domain { - domains: Domains, + pub domains: Domains, pub hiding: bool, pub capacity: usize, pub not_last_row: FieldColumn, From ba59436378de036da1da8b2c61ec49a244f549e3 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 16:17:41 +0300 Subject: [PATCH 24/36] tests cleaned up --- pasta-tree/src/auth_path/path.rs | 30 ++++++++++-------------------- pasta-tree/src/level/mod.rs | 26 +------------------------- pasta-tree/src/lib.rs | 32 +++++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 48 deletions(-) diff --git a/pasta-tree/src/auth_path/path.rs b/pasta-tree/src/auth_path/path.rs index ec6ea05..8ac27fe 100644 --- a/pasta-tree/src/auth_path/path.rs +++ b/pasta-tree/src/auth_path/path.rs @@ -23,8 +23,8 @@ impl AuthenticationPath where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { fn with_blinding(&self, rng: &mut R) -> AuthenticationPathWithBlinding { let mut path_0 = Vec::with_capacity(self.c0_path.len()); @@ -84,7 +84,7 @@ where Some(c0_nodes) => { debug_assert_eq!(parent_on_c0, c0_nodes.path_node()); (parent_on_c0 == c0_nodes.path_node()).ok_or(())?; - parent_on_c1 = c0_nodes .compute_parent(¶ms.c1_params)?; + parent_on_c1 = c0_nodes.compute_parent(¶ms.c1_params)?; } None => return Ok(CycleSide::C0(parent_on_c0)), } @@ -96,33 +96,23 @@ where #[cfg(test)] mod tests { use super::*; - use ark_std::test_rng; - use w3f_plonk_common::test_helpers::random_vec; + use ark_std::{test_rng, UniformRand}; + use crate::tests::random_node; #[test] fn test_auth_path() { let rng = &mut test_rng(); let domain_size = 2usize.pow(9); - let params = CycleParams::::setup(domain_size, rng); + let params = CycleParams::::setup(domain_size, rng);; - let c0_capacity = params.c0_params.piop_params.keyset_part_size; - let leaves = random_vec::(c0_capacity, rng); - let leaf_index = rng.gen_range(0..c0_capacity); - let leaf = leaves[leaf_index]; - let leaves = LevelWitness::new(leaves, leaf_index).unwrap(); - let innner_parent = leaves.compute_parent(¶ms.c1_params).unwrap(); - - let c1_capacity = params.c1_params.piop_params.keyset_part_size; - let parent_index = rng.gen_range(0..c1_capacity); - let mut inner_nodes = random_vec::(c1_capacity, rng); - inner_nodes[parent_index] = innner_parent; - let inner_nodes = LevelWitness::new(inner_nodes, parent_index).unwrap(); - let root = inner_nodes.compute_parent(¶ms.c0_params).unwrap(); + let leaf = ark_pallas::Affine::rand(rng); + let (l1_parent, leaves) = random_node(¶ms.c1_params, leaf, rng); + let (root, l1_nodes) = random_node(¶ms.c0_params, l1_parent, rng); let path = AuthenticationPath { c0_path: vec![leaves.clone()], - c1_path: vec![inner_nodes.clone()], + c1_path: vec![l1_nodes.clone()], }; assert_eq!(path.get_leaf(), leaf); diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index 6e32ebc..29ca1a5 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -37,31 +37,7 @@ mod tests { use ark_std::{end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; use w3f_plonk_common::test_helpers::random_vec; - - fn random_witness, R: Rng>( - params: &CycleSideParams, - path_node: G, - rng: &mut R, - ) -> LevelWitness { - let capacity = params.piop_params.keyset_part_size; - let mut nodes = random_vec::(capacity, rng); - let i = rng.gen_range(0..capacity); - nodes[i] = path_node; - LevelWitness { - siblings: nodes, - path_node_idx: i, - } - } - - fn random_node, R: Rng>( - params: &CycleSideParams, - path_node: G, - rng: &mut R, - ) -> (C::Affine, LevelWitness) { - let level_witness = random_witness(params, path_node, rng); - let parent = level_witness.compute_parent(params).unwrap(); - (parent, level_witness) - } + use crate::tests::random_node; fn _test_level_proof() where diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index f88007e..2b97a44 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -34,8 +34,8 @@ impl CycleParams where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { pub fn setup(domain_size: usize, rng: &mut R) -> Self { let setup_degree = 3 * domain_size; @@ -64,7 +64,6 @@ fn piop_params, R: Rng>(domain_size: usize, } impl> CycleSideParams { - pub fn commit_children( &self, children: &[G], @@ -213,10 +212,37 @@ mod tests { #[cfg(feature = "parallel")] use rayon::prelude::*; use w3f_plonk_common::domain::Domain; + use crate::auth_path::node::LevelWitness; type PallasIPA = IPA; type PallasC = WrappedAffine; + + fn random_witness, R: Rng>( + params: &CycleSideParams, + path_node: G, + rng: &mut R, + ) -> LevelWitness { + let capacity = params.piop_params.keyset_part_size; + let mut nodes = random_vec::(capacity, rng); + let i = rng.gen_range(0..capacity); + nodes[i] = path_node; + LevelWitness { + siblings: nodes, + path_node_idx: i, + } + } + + pub fn random_node, R: Rng>( + params: &CycleSideParams, + path_node: G, + rng: &mut R, + ) -> (C::Affine, LevelWitness) { + let level_witness = random_witness(params, path_node, rng); + let parent = level_witness.compute_parent(params).unwrap(); + (parent, level_witness) + } + fn setup, G: AffineRepr>( rng: &mut R, domain_size: usize, From 668f355d04f259d6dfe6bfe91f39bc6503b8befe Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 17:27:09 +0300 Subject: [PATCH 25/36] random_path --- pasta-tree/src/auth_path/mod.rs | 2 +- pasta-tree/src/auth_path/path.rs | 27 ++++++---------------- pasta-tree/src/level/mod.rs | 12 ++++------ pasta-tree/src/lib.rs | 39 ++++++++++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/pasta-tree/src/auth_path/mod.rs b/pasta-tree/src/auth_path/mod.rs index 5a14038..0124ba3 100644 --- a/pasta-tree/src/auth_path/mod.rs +++ b/pasta-tree/src/auth_path/mod.rs @@ -1,3 +1,3 @@ -mod blinded; +pub mod blinded; pub mod node; pub mod path; diff --git a/pasta-tree/src/auth_path/path.rs b/pasta-tree/src/auth_path/path.rs index 8ac27fe..e7dd83d 100644 --- a/pasta-tree/src/auth_path/path.rs +++ b/pasta-tree/src/auth_path/path.rs @@ -14,9 +14,9 @@ use ark_std::rand::Rng; /// otherwise it's the root. pub struct AuthenticationPath { /// Nodes on the `C0` curve. - c0_path: Vec>, + pub c0_path: Vec>, /// Nodes on the `C1` curve. - c1_path: Vec>, + pub c1_path: Vec>, } impl AuthenticationPath @@ -26,7 +26,7 @@ where C0: CurveGroup, C1: CurveGroup, { - fn with_blinding(&self, rng: &mut R) -> AuthenticationPathWithBlinding { + pub fn with_blinding(&self, rng: &mut R) -> AuthenticationPathWithBlinding { let mut path_0 = Vec::with_capacity(self.c0_path.len()); let mut path_1 = Vec::with_capacity(self.c1_path.len()); @@ -97,7 +97,7 @@ where mod tests { use super::*; use ark_std::{test_rng, UniformRand}; - use crate::tests::random_node; + use crate::tests::{random_nodes, random_path}; #[test] fn test_auth_path() { @@ -106,25 +106,12 @@ mod tests { let domain_size = 2usize.pow(9); let params = CycleParams::::setup(domain_size, rng);; - let leaf = ark_pallas::Affine::rand(rng); - let (l1_parent, leaves) = random_node(¶ms.c1_params, leaf, rng); - let (root, l1_nodes) = random_node(¶ms.c0_params, l1_parent, rng); - - let path = AuthenticationPath { - c0_path: vec![leaves.clone()], - c1_path: vec![l1_nodes.clone()], - }; + let (leaf, path, root) = random_path(¶ms, 2, rng); assert_eq!(path.get_leaf(), leaf); - match path.compute_root(¶ms).unwrap() { - CycleSide::C0(root_) => assert_eq!(root_, root), - _ => panic!(), - } + assert_eq!(path.compute_root(¶ms).unwrap(), root); let path_with_bfs = path.with_blinding(rng); - match path_with_bfs.compute_root(¶ms).unwrap() { - CycleSide::C0(root_) => assert_eq!(root_, root), - _ => panic!(), - } + assert_eq!(path_with_bfs.compute_root(¶ms).unwrap(), root); } } diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index 29ca1a5..cce606c 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -26,18 +26,14 @@ type IPACommitment = as PCS<::ScalarField>>::C #[cfg(test)] mod tests { - use crate::auth_path::node::LevelWitness; + use crate::tests::random_nodes; use crate::CycleParams; - use crate::CycleSideParams; use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; - use ark_ec::{AffineRepr, CurveGroup}; + use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_pallas::PallasConfig; - use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, test_rng, UniformRand}; use ark_vesta::VestaConfig; - use w3f_plonk_common::test_helpers::random_vec; - use crate::tests::random_node; fn _test_level_proof() where @@ -55,8 +51,8 @@ mod tests { } = CycleParams::, Projective>::setup(domain_size, rng); let leaf = Affine::::rand(rng); - let (l1_node, mut l2_nodes) = random_node(&c1_params, leaf, rng); - let (root, l1_nodes) = random_node(&c0_params, l1_node, rng); + let (l1_node, mut l2_nodes) = random_nodes(&c1_params, leaf, rng); + let (root, l1_nodes) = random_nodes(&c0_params, l1_node, rng); let (_, l1_vk) = c0_params.commit_children(l1_nodes.siblings.as_slice(), F0::zero()); let root_fc = l1_vk.fixed_columns_committed; diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 2b97a44..14106f8 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -6,6 +6,7 @@ use ark_ff::{PrimeField, Zero}; use ark_std::rand::Rng; use std::marker::PhantomData; use w3f_pcs::aggregation::multiple::Transcript; +use w3f_pcs::pcs::kzg::commitment::WrappedAffine; use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::PCS; use w3f_plonk_common::domain::Domain; @@ -161,6 +162,7 @@ impl> CycleSideParams { C0(C0), C1(C1), @@ -209,10 +211,11 @@ mod tests { use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::{index, ArkTranscript, PiopParams}; + use crate::auth_path::node::LevelWitness; + use crate::auth_path::path::AuthenticationPath; #[cfg(feature = "parallel")] use rayon::prelude::*; use w3f_plonk_common::domain::Domain; - use crate::auth_path::node::LevelWitness; type PallasIPA = IPA; type PallasC = WrappedAffine; @@ -233,7 +236,7 @@ mod tests { } } - pub fn random_node, R: Rng>( + pub fn random_nodes, R: Rng>( params: &CycleSideParams, path_node: G, rng: &mut R, @@ -243,6 +246,38 @@ mod tests { (parent, level_witness) } + pub fn random_path, R: Rng>(params: &CycleParams, length: usize, rng: &mut R) -> (C0::Affine, AuthenticationPath, CycleSide) { + let c0_len = (length + 1) / 2; + let c1_len = length / 2; + debug_assert_eq!(c0_len + c1_len, length); + let mut c0_path = Vec::with_capacity(c0_len); + let mut c1_path = Vec::with_capacity(c1_len); + + let leaf = C0::Affine::rand(rng); + let mut c0_path_node = leaf; + for _ in 0..c1_len { + let (parent_on_c1, c0_nodes) = random_nodes(¶ms.c1_params, c0_path_node, rng); + let (parent_on_c0, c1_nodes) = random_nodes(¶ms.c0_params, parent_on_c1, rng); + c0_path_node = parent_on_c0; + c0_path.push(c0_nodes); + c1_path.push(c1_nodes); + } + + let root = if c0_len > c1_len { + let (root_on_c1, c0_nodes) = random_nodes(¶ms.c1_params, c0_path_node, rng); + c0_path.push(c0_nodes); + CycleSide::C1(root_on_c1) + } else { + CycleSide::C0(c0_path_node) + }; + + let path = AuthenticationPath { + c0_path, + c1_path, + }; + (leaf, path, root) + } + fn setup, G: AffineRepr>( rng: &mut R, domain_size: usize, From 9dc9a7d9c4192f1db66fde11151566fbd6702777 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 20:44:13 +0300 Subject: [PATCH 26/36] prove/verify --- pasta-tree/src/auth_path/blinded.rs | 21 ++++++ pasta-tree/src/level/mod.rs | 3 - pasta-tree/src/level/prover.rs | 19 +---- pasta-tree/src/level/verifier.rs | 4 +- pasta-tree/src/lib.rs | 52 ++++++++++++- pasta-tree/src/prover.rs | 102 +++++++++++++++++++++++++ pasta-tree/src/verifier.rs | 113 ++++++++++++++++++++++++++++ 7 files changed, 289 insertions(+), 25 deletions(-) create mode 100644 pasta-tree/src/prover.rs create mode 100644 pasta-tree/src/verifier.rs diff --git a/pasta-tree/src/auth_path/blinded.rs b/pasta-tree/src/auth_path/blinded.rs index 47a82fd..ab87f9c 100644 --- a/pasta-tree/src/auth_path/blinded.rs +++ b/pasta-tree/src/auth_path/blinded.rs @@ -8,6 +8,12 @@ pub struct AuthenticationPathWithBlinding { pub(crate) c1_path: Vec>, } +#[derive(Clone, Debug)] +pub struct BlindedAuthenticationPath { + pub(crate) c0_path: Vec, + pub(crate) c1_path: Vec, +} + impl AuthenticationPathWithBlinding where F0: PrimeField, @@ -15,6 +21,21 @@ where C0: CurveGroup, C1: CurveGroup, { + pub(crate) fn apply_bfs( + &self, + params: &CycleParams, + ) -> BlindedAuthenticationPath { + let c0_path = self.c0_path.iter() + .map(|c0_level| c0_level.blinded_path_node(¶ms.c0_params.pcs_params).unwrap()) + .collect(); + let c1_path = self.c1_path.iter() + .map(|c1_level| c1_level.blinded_path_node(¶ms.c1_params.pcs_params).unwrap()) + .collect(); + BlindedAuthenticationPath { + c0_path, + c1_path, + } + } pub(crate) fn compute_root( &self, params: &CycleParams, diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index cce606c..f7c989f 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -21,9 +21,6 @@ pub struct LevelProof { todo: Coeffs, } -type IPACommitment = as PCS<::ScalarField>>::C; - - #[cfg(test)] mod tests { use crate::tests::random_nodes; diff --git a/pasta-tree/src/level/prover.rs b/pasta-tree/src/level/prover.rs index 239d43c..90f84ce 100644 --- a/pasta-tree/src/level/prover.rs +++ b/pasta-tree/src/level/prover.rs @@ -1,7 +1,7 @@ use crate::auth_path::node::LevelWitnessWithBlinding; use crate::ipa_hiding::HidingIpa; -use crate::level::{IPACommitment, LevelProof}; -use crate::{Coeffs, CycleSideParams}; +use crate::level::LevelProof; +use crate::{Coeffs, CycleSideParams, IPACommitment}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; use ark_poly::Polynomial; @@ -14,24 +14,11 @@ use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ArkTranscript; -// // Witness for the relation (C, C'; i, r, r', x1, ..., xn, yi | C = x1.G1 + ...+ xn.Gn + r'H, C' = (xi, yi) + r.H') -// pub struct LevelWitness { -// pub siblings: Vec>, -// pub i: usize, -// pub child_r: G::ScalarField, -// pub parent_r: G::BaseField, -// // TODO: precompute C -// } impl> CycleSideParams> { - // to prove a single level, the prover needs: - // 1. witness data: - // - parent randomizer - // - siblings - // - child index - // 2. level params + pub fn prove_level( &self, witness: &LevelWitnessWithBlinding>, diff --git a/pasta-tree/src/level/verifier.rs b/pasta-tree/src/level/verifier.rs index 9f1070c..49bc825 100644 --- a/pasta-tree/src/level/verifier.rs +++ b/pasta-tree/src/level/verifier.rs @@ -1,6 +1,6 @@ use crate::ipa_hiding::HidingIpa; -use crate::level::{IPACommitment, LevelProof}; -use crate::CycleSideParams; +use crate::level::LevelProof; +use crate::{CycleSideParams, IPACommitment}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; use ark_std::{end_timer, start_timer}; diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 14106f8..a4aef02 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,7 +1,7 @@ #![feature(bool_to_result)] use crate::ipa_hiding::HidingIpa; -use ark_ec::{AffineRepr, CurveGroup}; +use ark_ec::{AffineRepr, CurveGroup, PrimeGroup}; use ark_ff::{PrimeField, Zero}; use ark_std::rand::Rng; use std::marker::PhantomData; @@ -9,14 +9,20 @@ use w3f_pcs::aggregation::multiple::Transcript; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::PCS; +use w3f_pcs::shplonk::AggregateProof; use w3f_plonk_common::domain::Domain; -use w3f_ring_proof::piop::FixedColumns; +use w3f_plonk_common::PiopProof; +use w3f_ring_proof::piop::{FixedColumns, RingCommitments, RingEvaluations}; use w3f_ring_proof::{FixedColumnsCommitted, PiopParams, VerifierKey}; -mod auth_path; +pub mod auth_path; pub mod ipa_hiding; pub mod level; +pub mod prover; +pub mod verifier; + +type IPACommitment = as PCS<::ScalarField>>::C; struct CycleSideParams> { pcs_params: HidingIpa, @@ -31,6 +37,18 @@ struct CycleParams< c1_params: CycleSideParams, } +pub struct CycleSideProof> { + piop_proofs: Vec, RingCommitments>, RingEvaluations>>, + pcs_proof: AggregateProof>, + todo: Coeffs, + fixed_columns_committed: Vec>>, +} + +pub struct CurveTreeProof, C1: CurveGroup> { + c0_proof: CycleSideProof, + c1_proof: CycleSideProof, +} + impl CycleParams where F0: PrimeField, @@ -187,7 +205,7 @@ mod tests { use super::*; use ark_ec::scalar_mul::glv::GLVConfig; use ark_ec::scalar_mul::wnaf::WnafContext; - use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; + use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ec::AdditiveGroup; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; @@ -199,6 +217,7 @@ mod tests { use ark_std::rand::Rng; use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; use std::collections::BTreeSet; + use ark_vesta::VestaConfig; use w3f_pcs::pcs::ipa::IPA; use w3f_pcs::pcs::kzg::commitment::WrappedAffine; use w3f_pcs::pcs::PcsParams; @@ -289,6 +308,31 @@ mod tests { (pcs_params, piop_params) } + fn _test_proof() + where + F0: PrimeField, + F1: PrimeField, + C0: SWCurveConfig, + C1: SWCurveConfig, + { + let rng = &mut test_rng(); + + let domain_size = 2usize.pow(9); + let params = CycleParams::, Projective>::setup(domain_size, rng); + let (leaf, path, root) = random_path(¶ms, 2, rng); + + let (auth_path, proof) = params.prove(path, rng); + + assert!(params.verify(auth_path, proof, root)); + } + + // cargo test test_level_proof --release --features="print-trace" -- --show-output + // cargo test test_level_proof --release --features="print-trace parallel" -- --show-output + #[test] + fn test_proof() { + _test_proof::<_, _, PallasConfig, VestaConfig>(); + } + // // cargo test test_pasta_ring_plonk --release --features="print-trace" -- --show-output // #[test] // fn test_pasta_ring_plonk() { diff --git a/pasta-tree/src/prover.rs b/pasta-tree/src/prover.rs new file mode 100644 index 0000000..5486984 --- /dev/null +++ b/pasta-tree/src/prover.rs @@ -0,0 +1,102 @@ +use crate::auth_path::node::LevelWitnessWithBlinding; +use crate::auth_path::path::AuthenticationPath; +use crate::ipa_hiding::HidingIpa; +use crate::{Coeffs, CurveTreeProof, CycleParams, CycleSideParams, CycleSideProof, IPACommitment}; +use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; +use ark_ec::CurveGroup; +use ark_ff::PrimeField; +use ark_std::rand::Rng; +use ark_std::UniformRand; +use std::collections::BTreeSet; +use w3f_pcs::pcs::PcsParams; +use w3f_pcs::shplonk::Shplonk; +use w3f_plonk_common::piop::ProverPiop; +use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; +use w3f_ring_proof::piop::prover::PiopProver; +use w3f_ring_proof::ArkTranscript; +use crate::auth_path::blinded::BlindedAuthenticationPath; + +impl CycleParams, Projective> +where + F0: PrimeField, + F1: PrimeField, + C0: SWCurveConfig, + C1: SWCurveConfig, +{ + pub fn prove(&self, auth_path: AuthenticationPath, Projective>, rng: &mut R) -> ( + BlindedAuthenticationPath, Projective>, + CurveTreeProof, Projective> + ) { + let auth_path_with_bf = auth_path.with_blinding(rng); + let blinded_auth_path = auth_path_with_bf.apply_bfs(&self); + let blinded_auth_path2 = blinded_auth_path.clone(); + let c0_proof = self.c0_params.prove_side(blinded_auth_path.c1_path, &auth_path_with_bf.c1_path, rng); + let c1_proof = self.c1_params.prove_side(blinded_auth_path.c0_path, &auth_path_with_bf.c0_path, rng); + (blinded_auth_path2, CurveTreeProof { + c0_proof, + c1_proof, + }) + } +} + +impl> CycleSideParams> +{ + pub fn prove_side( + &self, + blinded_path: Vec>, + witness: &[LevelWitnessWithBlinding>], + rng: &mut R, + ) -> CycleSideProof { + debug_assert_eq!(blinded_path.len(), witness.len()); + let mut piop_proofs = Vec::with_capacity(witness.len()); + let mut fixed_columns_committed = Vec::with_capacity(witness.len()); + let mut polys = Vec::with_capacity(witness.len() * 9); + let mut coords = Vec::with_capacity(witness.len() * 9); + + let plonk_prover = PlonkProver::, _>::init( + self.pcs_params.ck(), + blinded_path.clone(), + ArkTranscript::new(b"pasta-tree-level-proof"), + ); + + for (level, blinded_node) in witness.iter().zip(blinded_path.into_iter()) { + let (fixed_columns, verifier_key) = self.commit_children(&level.level_witness.siblings, level.parent_bf); + // debug_assert_eq!(verifier_key.fixed_columns_committed.points[0].0, *blinded_node); + fixed_columns_committed.push(verifier_key.fixed_columns_committed); + let piop = PiopProver::build(&self.piop_params, fixed_columns, level.level_witness.path_node_idx, level.bf); + let blinded_node_ = > as ProverPiop>>::result(&piop); + debug_assert_eq!(blinded_node_, blinded_node); + let (pcs_openings, piop_proof, mut transcript) = plonk_prover.reduce_to_pcs_opening(piop); + piop_proofs.push(piop_proof); + let PcsOpeningAt2Points { + polys_at_zeta, + polys_at_zeta_omega, + zeta, + zeta_omega, + } = pcs_openings; + + coords.extend(vec![BTreeSet::from([zeta]); polys_at_zeta.len()]); + polys.extend(polys_at_zeta); + coords.extend(vec![BTreeSet::from([zeta_omega]); polys_at_zeta_omega.len()]); + polys.extend(polys_at_zeta_omega); + } + + let parent_bf = witness.iter().map(|level| level.parent_bf).sum(); + let todo = Coeffs(C::ScalarField::rand(rng), C::ScalarField::rand(rng)); + let pcs_proof = Shplonk::>::open_many( + &self.pcs_params, + &polys, + &coords, + parent_bf, + &mut todo.clone(), + ); + + let proof = CycleSideProof { + piop_proofs, + pcs_proof, + todo, + fixed_columns_committed, + }; + proof + } +} \ No newline at end of file diff --git a/pasta-tree/src/verifier.rs b/pasta-tree/src/verifier.rs new file mode 100644 index 0000000..362adf0 --- /dev/null +++ b/pasta-tree/src/verifier.rs @@ -0,0 +1,113 @@ +use crate::ipa_hiding::HidingIpa; +use crate::{CurveTreeProof, CycleParams, CycleSide, CycleSideParams, CycleSideProof}; +use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; +use ark_ec::CurveGroup; +use ark_ff::PrimeField; +use ark_std::rand::Rng; +use w3f_pcs::pcs::PcsParams; +use w3f_pcs::shplonk::Shplonk; +use w3f_plonk_common::verifier::{PcsOpeningAt2Points, PlonkVerifier}; +use w3f_ring_proof::piop::verifier::PiopVerifier; +use w3f_ring_proof::ArkTranscript; +use crate::auth_path::blinded::BlindedAuthenticationPath; +use crate::auth_path::path::AuthenticationPath; + +impl CycleParams, Projective> +where + F0: PrimeField, + F1: PrimeField, + C0: SWCurveConfig, + C1: SWCurveConfig, +{ + pub fn verify(&self, auth_path: BlindedAuthenticationPath, Projective>, + proof: CurveTreeProof, Projective>, + root: CycleSide, Affine>) -> bool { + let c0_x_coords: Vec> = proof.c0_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); + let c1_x_coords: Vec> = proof.c1_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); + + // match root { + // CycleSide::C0(c0_root) => { + // assert_eq!(c0_root, c0_x_coords[c0_x_coords.len() - 1]); + // assert_eq!(auth_path.c1_path, c1_x_coords); + // assert_eq!(auth_path.c0_path[1..], c0_x_coords[..c0_x_coords.len() - 1]); + // } + // CycleSide::C1(c1_root) => { + // assert_eq!(c1_root, c1_x_coords[c1_x_coords.len() - 1]); + // } + // } + let c0_proof = self.c0_params.verify_side(auth_path.c1_path, proof.c0_proof); + let c1_proof = self.c1_params.verify_side(auth_path.c0_path, proof.c1_proof); + c0_proof && c1_proof + } +} + +impl> CycleSideParams> +{ + pub fn verify_side( + &self, + // parent: FixedColumnsCommitted>, + blinded_path: Vec>, + side_proof: CycleSideProof, + ) -> bool { + let plonk_verifier: PlonkVerifier, _> = PlonkVerifier::init( + self.pcs_params.vk(), + &blinded_path, + ArkTranscript::new(b"pasta-tree-level-proof"), + ); + + let mut polys = Vec::with_capacity(side_proof.piop_proofs.len() * 9); + let mut coords = Vec::with_capacity(side_proof.piop_proofs.len() * 9); + let mut vals = Vec::with_capacity(side_proof.piop_proofs.len() * 9); + + for ((blinded_node, piop_proof), parent) in blinded_path.iter() + .zip(side_proof.piop_proofs.into_iter()) + .zip(side_proof.fixed_columns_committed.into_iter()) { + let (challenges, mut rng) = plonk_verifier.restore_challenges( + blinded_node, + &piop_proof, + // '1' accounts for the quotient polynomial that is aggregated together with the columns + 8, + 7, + ); + let seed = self.piop_params.seed; + let seed_plus_result = (seed + blinded_node).into_affine(); + let domain_at_zeta = self.piop_params.domain.evaluate(challenges.zeta); + let piop = PiopVerifier::<_, _, Affine>::init( + domain_at_zeta, + parent, + piop_proof.column_commitments.clone(), + piop_proof.columns_at_zeta.clone(), + (seed.x, seed.y), + (seed_plus_result.x, seed_plus_result.y), + ); + + let PcsOpeningAt2Points { + open_at_zeta, + open_at_zeta_omega, + zeta, + zeta_omega, + vals_at_zeta, + vals_at_zeta_omega, + } = plonk_verifier.evaluate_piop(piop, piop_proof, challenges); + + 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])); + } + + let mut todo = side_proof.todo; + + let valid = Shplonk::>::verify_many( + &self.pcs_params.vk(), + &polys, + side_proof.pcs_proof, + &coords, + &vals, + &mut todo, + ); + valid + } +} From 3f01d296fc247dda45bf050a3b337d711a77e74a Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 21:46:32 +0300 Subject: [PATCH 27/36] debug --- pasta-tree/src/lib.rs | 2 +- pasta-tree/src/prover.rs | 3 +++ pasta-tree/src/verifier.rs | 29 +++++++++++++++++------------ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index a4aef02..548a03a 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -319,7 +319,7 @@ mod tests { let domain_size = 2usize.pow(9); let params = CycleParams::, Projective>::setup(domain_size, rng); - let (leaf, path, root) = random_path(¶ms, 2, rng); + let (leaf, path, root) = random_path(¶ms, 3, rng); let (auth_path, proof) = params.prove(path, rng); diff --git a/pasta-tree/src/prover.rs b/pasta-tree/src/prover.rs index 5486984..b7f5352 100644 --- a/pasta-tree/src/prover.rs +++ b/pasta-tree/src/prover.rs @@ -75,6 +75,9 @@ impl, Projective>, proof: CurveTreeProof, Projective>, root: CycleSide, Affine>) -> bool { + println!("leaf = {}", auth_path.c0_path[0]); + println!("root = {:?}", root); let c0_x_coords: Vec> = proof.c0_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); let c1_x_coords: Vec> = proof.c1_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); - - // match root { - // CycleSide::C0(c0_root) => { - // assert_eq!(c0_root, c0_x_coords[c0_x_coords.len() - 1]); - // assert_eq!(auth_path.c1_path, c1_x_coords); - // assert_eq!(auth_path.c0_path[1..], c0_x_coords[..c0_x_coords.len() - 1]); - // } - // CycleSide::C1(c1_root) => { - // assert_eq!(c1_root, c1_x_coords[c1_x_coords.len() - 1]); - // } - // } + match root { + CycleSide::C0(c0_root) => { + assert_eq!(c0_root, c0_x_coords[c0_x_coords.len() - 1]); + assert_eq!(auth_path.c1_path, c1_x_coords); + assert_eq!(auth_path.c0_path[1..], c0_x_coords[..c0_x_coords.len() - 1]); + } + CycleSide::C1(c1_root) => { + assert_eq!(c1_root, c1_x_coords[c1_x_coords.len() - 1]); + assert_eq!(auth_path.c1_path, c1_x_coords[..c1_x_coords.len() - 1]); + assert_eq!(auth_path.c0_path[1..], c0_x_coords); + } + } let c0_proof = self.c0_params.verify_side(auth_path.c1_path, proof.c0_proof); + assert!(c0_proof); let c1_proof = self.c1_params.verify_side(auth_path.c0_path, proof.c1_proof); + assert!(c1_proof); c0_proof && c1_proof } } @@ -45,7 +50,6 @@ impl>, blinded_path: Vec>, side_proof: CycleSideProof, ) -> bool { @@ -89,6 +93,7 @@ impl Date: Mon, 18 May 2026 03:51:43 +0300 Subject: [PATCH 28/36] non-hiding lol --- pasta-tree/src/auth_path/node.rs | 4 +-- pasta-tree/src/level/prover.rs | 7 ++-- pasta-tree/src/lib.rs | 57 ++++++++++++++++++++++++++++++-- pasta-tree/src/prover.rs | 11 +++--- pasta-tree/src/verifier.rs | 36 +++++++++----------- 5 files changed, 81 insertions(+), 34 deletions(-) diff --git a/pasta-tree/src/auth_path/node.rs b/pasta-tree/src/auth_path/node.rs index 95ef451..d6333ff 100644 --- a/pasta-tree/src/auth_path/node.rs +++ b/pasta-tree/src/auth_path/node.rs @@ -40,8 +40,8 @@ impl LevelWitness { ) -> LevelWitnessWithBlinding { LevelWitnessWithBlinding { level_witness: self.clone(), - bf: self_bf, - parent_bf, + bf: G::ScalarField::zero(), //self_bf, + parent_bf: G::BaseField::zero(), //parent_bf, } } diff --git a/pasta-tree/src/level/prover.rs b/pasta-tree/src/level/prover.rs index 90f84ce..60bb142 100644 --- a/pasta-tree/src/level/prover.rs +++ b/pasta-tree/src/level/prover.rs @@ -8,7 +8,10 @@ use ark_poly::Polynomial; use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, UniformRand}; use std::collections::BTreeSet; -use w3f_pcs::pcs::PcsParams; +use ark_ff::PrimeField; +use ark_std::iterable::Iterable; +use w3f_pcs::aggregation::multiple::{MultipointClaim, Transcript}; +use w3f_pcs::pcs::{PcsParams, PCS}; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; @@ -77,4 +80,4 @@ impl, } +#[derive(Clone)] pub struct CycleSideProof> { piop_proofs: Vec, RingCommitments>, RingEvaluations>>, pcs_proof: AggregateProof>, @@ -44,6 +45,7 @@ pub struct CycleSideProof> { fixed_columns_committed: Vec>>, } +#[derive(Clone)] pub struct CurveTreeProof, C1: CurveGroup> { c0_proof: CycleSideProof, c1_proof: CycleSideProof, @@ -225,7 +227,7 @@ mod tests { use w3f_pcs::shplonk::Shplonk; use w3f_pcs::Poly; use w3f_plonk_common::piop::ProverPiop; - use w3f_plonk_common::prover::PlonkProver; + use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; use w3f_plonk_common::test_helpers::random_vec; use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::{index, ArkTranscript, PiopParams}; @@ -319,11 +321,60 @@ mod tests { let domain_size = 2usize.pow(9); let params = CycleParams::, Projective>::setup(domain_size, rng); - let (leaf, path, root) = random_path(¶ms, 3, rng); + let (leaf, path, wrapped_root) = random_path(¶ms, 4, rng); + let root = match wrapped_root { + CycleSide::C0(root) => root, + _ => panic!() + }; + + let path_with_bf = path.with_blinding(rng); + // let l1_nodes = &path_with_bf.c1_path[1]; + // let l2_nodes = &path_with_bf.c0_path[1]; + // let l3_nodes = &path_with_bf.c1_path[0]; + // let l4_nodes = &path_with_bf.c0_path[0]; + // + // let (_, l1_vk) = params.c0_params.commit_children(l1_nodes.level_witness.siblings.as_slice(), l1_nodes.parent_bf); + // let root_fc = l1_vk.fixed_columns_committed; + // assert_eq!(root_fc.points[0].0, root); + // + // let (l1_node_blinded, l1_proof) = params.c0_params.prove_level(l1_nodes, rng); + // assert!(params.c0_params.verify_level(root_fc, l1_node_blinded, l1_proof)); + // + // let (_, l2_vk) = params.c1_params.commit_children(l2_nodes.level_witness.siblings.as_slice(), l2_nodes.parent_bf); + // let l2_node_fc = l2_vk.fixed_columns_committed; + // assert_eq!(l2_node_fc.points[0].0, l1_node_blinded); + // + // let (l2_node_blinded, l2_proof) = params.c1_params.prove_level(l2_nodes, rng); + // assert!(params.c1_params.verify_level(l2_node_fc, l2_node_blinded, l2_proof)); + // + // let (_, l3_vk) = params.c0_params.commit_children(l3_nodes.level_witness.siblings.as_slice(), l3_nodes.parent_bf); + // let l3_node_fc = l3_vk.fixed_columns_committed; + // assert_eq!(l3_node_fc.points[0].0, l2_node_blinded); + // + // let (l3_node_blinded, l3_proof) = params.c0_params.prove_level(l3_nodes, rng); + // assert!(params.c0_params.verify_level(l3_node_fc, l3_node_blinded, l3_proof)); + // + // let (_, l4_vk) = params.c1_params.commit_children(l4_nodes.level_witness.siblings.as_slice(), l4_nodes.parent_bf); + // let l4_node_fc = l4_vk.fixed_columns_committed; + // assert_eq!(l4_node_fc.points[0].0, l3_node_blinded); + // + // let (l4_node_blinded, l4_proof) = params.c1_params.prove_level(l4_nodes, rng); + // assert!(params.c1_params.verify_level(l4_node_fc, l4_node_blinded, l4_proof)); let (auth_path, proof) = params.prove(path, rng); - assert!(params.verify(auth_path, proof, root)); + // assert_eq!(auth_path.c0_path, vec![l4_node_blinded, l2_node_blinded]); + // assert_eq!(auth_path.c1_path, vec![l3_node_blinded, l1_node_blinded]); + // + // assert!(params.c0_params.verify_side(auth_path.c1_path, proof.c0_proof.clone())); + // + // assert_eq!(proof.c1_proof.fixed_columns_committed.len(), 2); + // assert_eq!(proof.c1_proof.fixed_columns_committed[0].points[0].0, l3_node_blinded); + // assert_eq!(proof.c1_proof.fixed_columns_committed[1].points[0].0, l1_node_blinded); + // + // assert!(params.c1_params.verify_side(auth_path.c0_path, proof.c1_proof.clone())); + + assert!(params.verify(auth_path, proof, wrapped_root)); } // cargo test test_level_proof --release --features="print-trace" -- --show-output diff --git a/pasta-tree/src/prover.rs b/pasta-tree/src/prover.rs index b7f5352..102f3b8 100644 --- a/pasta-tree/src/prover.rs +++ b/pasta-tree/src/prover.rs @@ -1,3 +1,4 @@ +use crate::auth_path::blinded::BlindedAuthenticationPath; use crate::auth_path::node::LevelWitnessWithBlinding; use crate::auth_path::path::AuthenticationPath; use crate::ipa_hiding::HidingIpa; @@ -14,7 +15,6 @@ use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ArkTranscript; -use crate::auth_path::blinded::BlindedAuthenticationPath; impl CycleParams, Projective> where @@ -29,10 +29,10 @@ where ) { let auth_path_with_bf = auth_path.with_blinding(rng); let blinded_auth_path = auth_path_with_bf.apply_bfs(&self); - let blinded_auth_path2 = blinded_auth_path.clone(); + let auth_path = blinded_auth_path.clone(); let c0_proof = self.c0_params.prove_side(blinded_auth_path.c1_path, &auth_path_with_bf.c1_path, rng); let c1_proof = self.c1_params.prove_side(blinded_auth_path.c0_path, &auth_path_with_bf.c0_path, rng); - (blinded_auth_path2, CurveTreeProof { + (auth_path, CurveTreeProof { c0_proof, c1_proof, }) @@ -74,10 +74,7 @@ impl CycleParams, Projective> where @@ -22,22 +20,22 @@ where pub fn verify(&self, auth_path: BlindedAuthenticationPath, Projective>, proof: CurveTreeProof, Projective>, root: CycleSide, Affine>) -> bool { - println!("leaf = {}", auth_path.c0_path[0]); - println!("root = {:?}", root); + // println!("leaf = {}", auth_path.c0_path[0]); + // println!("root = {:?}", root); let c0_x_coords: Vec> = proof.c0_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); let c1_x_coords: Vec> = proof.c1_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); - match root { - CycleSide::C0(c0_root) => { - assert_eq!(c0_root, c0_x_coords[c0_x_coords.len() - 1]); - assert_eq!(auth_path.c1_path, c1_x_coords); - assert_eq!(auth_path.c0_path[1..], c0_x_coords[..c0_x_coords.len() - 1]); - } - CycleSide::C1(c1_root) => { - assert_eq!(c1_root, c1_x_coords[c1_x_coords.len() - 1]); - assert_eq!(auth_path.c1_path, c1_x_coords[..c1_x_coords.len() - 1]); - assert_eq!(auth_path.c0_path[1..], c0_x_coords); - } - } + // match root { + // CycleSide::C0(c0_root) => { + // assert_eq!(c0_root, c0_x_coords[c0_x_coords.len() - 1]); + // assert_eq!(auth_path.c1_path, c1_x_coords); + // assert_eq!(auth_path.c0_path[1..], c0_x_coords[..c0_x_coords.len() - 1]); + // } + // CycleSide::C1(c1_root) => { + // assert_eq!(c1_root, c1_x_coords[c1_x_coords.len() - 1]); + // assert_eq!(auth_path.c1_path, c1_x_coords[..c1_x_coords.len() - 1]); + // assert_eq!(auth_path.c0_path[1..], c0_x_coords); + // } + // } let c0_proof = self.c0_params.verify_side(auth_path.c1_path, proof.c0_proof); assert!(c0_proof); let c1_proof = self.c1_params.verify_side(auth_path.c0_path, proof.c1_proof); @@ -93,8 +91,7 @@ impl>::verify_many( &self.pcs_params.vk(), &polys, From 3a4482f92890576971ca246dc5137c040a0c5144 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Wed, 20 May 2026 02:21:41 +0300 Subject: [PATCH 29/36] benches added --- pasta-tree/src/lib.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index e38e42f..7f80ea4 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -360,8 +360,10 @@ mod tests { // // let (l4_node_blinded, l4_proof) = params.c1_params.prove_level(l4_nodes, rng); // assert!(params.c1_params.verify_level(l4_node_fc, l4_node_blinded, l4_proof)); - + let t_prove = start_timer!(|| "Proving CurveTree membership, H=4, M=512, C=252"); let (auth_path, proof) = params.prove(path, rng); + end_timer!(t_prove); + // assert_eq!(auth_path.c0_path, vec![l4_node_blinded, l2_node_blinded]); // assert_eq!(auth_path.c1_path, vec![l3_node_blinded, l1_node_blinded]); @@ -374,11 +376,15 @@ mod tests { // // assert!(params.c1_params.verify_side(auth_path.c0_path, proof.c1_proof.clone())); - assert!(params.verify(auth_path, proof, wrapped_root)); + let t_verify = start_timer!(|| "Verifying CurveTree opening"); + let valid = params.verify(auth_path, proof, wrapped_root); + end_timer!(t_verify); + assert!(valid); + } - // cargo test test_level_proof --release --features="print-trace" -- --show-output - // cargo test test_level_proof --release --features="print-trace parallel" -- --show-output + // cargo test test_proof --release --features="print-trace" -- --show-output + // cargo test test_proof --release --features="print-trace parallel" -- --show-output #[test] fn test_proof() { _test_proof::<_, _, PallasConfig, VestaConfig>(); From 19d9190477fae5a4720745102e6c8fd6ac8067ae Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Wed, 20 May 2026 07:09:17 +0300 Subject: [PATCH 30/36] fix --- w3f-ring-proof/src/piop/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index a54a307..6fd12e1 100644 --- a/w3f-ring-proof/src/piop/mod.rs +++ b/w3f-ring-proof/src/piop/mod.rs @@ -165,7 +165,7 @@ impl VerifierKey> { ring: &Ring, kzg_vk: RawKzgVerifierKey, ) -> Self { - let fixed_columns = ring.as_fixed_columns(); + let fixed_columns = FixedColumnsCommitted::from_ring(&ring); Self::from_commitment_and_kzg_vk(fixed_columns, kzg_vk) } From 56987db6077b7cb22f0e4c71862c429e516760ca Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Wed, 20 May 2026 08:57:22 +0300 Subject: [PATCH 31/36] arkworks 0.6 --- pasta-tree/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pasta-tree/Cargo.toml b/pasta-tree/Cargo.toml index 1684883..75d7a48 100644 --- a/pasta-tree/Cargo.toml +++ b/pasta-tree/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/w3f/ring-proof" w3f-pcs.workspace = true w3f-plonk-common.workspace = true w3f-ring-proof = { path = "../w3f-ring-proof" } -ark-pallas = { version = "0.5", default-features = false, features = ["curve"] } -ark-vesta = { version = "0.5", default-features = false } +ark-pallas = { version = "0.6", default-features = false, features = ["curve"] } +ark-vesta = { version = "0.6", default-features = false } ark-transcript.workspace = true ark-std.workspace = true ark-ff.workspace = true From f0318db78243426efa605572447c4176106becd9 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Wed, 20 May 2026 08:58:24 +0300 Subject: [PATCH 32/36] hiding IPA moved to fflonk --- pasta-tree/src/ipa_hiding.rs | 194 ------------------------------- pasta-tree/src/level/mod.rs | 5 +- pasta-tree/src/level/prover.rs | 15 +-- pasta-tree/src/level/verifier.rs | 2 +- pasta-tree/src/lib.rs | 20 ++-- pasta-tree/src/prover.rs | 13 ++- pasta-tree/src/verifier.rs | 2 +- 7 files changed, 30 insertions(+), 221 deletions(-) delete mode 100644 pasta-tree/src/ipa_hiding.rs diff --git a/pasta-tree/src/ipa_hiding.rs b/pasta-tree/src/ipa_hiding.rs deleted file mode 100644 index 8a2f4a2..0000000 --- a/pasta-tree/src/ipa_hiding.rs +++ /dev/null @@ -1,194 +0,0 @@ -use ark_ec::CurveGroup; -use ark_ff::{PrimeField, Zero}; -use ark_poly::{DenseUVPolynomial, Polynomial}; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use ark_std::UniformRand; -use ark_std::rand::Rng; -use w3f_pcs::Poly; -use w3f_pcs::pcs::PCS; -use w3f_pcs::pcs::ipa::ipa_pc; -use w3f_pcs::pcs::kzg::commitment::WrappedAffine; -use w3f_pcs::pcs::{CommitterKey, PcsParams, RawVerifierKey, VerifierKey, ipa}; - -// To open a hiding commitment `Cp = Commit(p, t1) = (p0.G0 + ... + pn.Gn) + t1.H` at `z`, -// the prover: -// 1. Computes a hiding commitment to a random `q` such that `deg(q) = deg(p)` and `q(z) = 0` -// `Cq = Commit(q, t2) = (q0.G0 + ... + qn.Gn) + t2.H`. -// 2. Computes the blinded polynomial `p' = p + a.q`, p'(z) = p(z) + a.q(z) = p(z)`. -// 3. Opens the non-hiding commitment `Cp' = Commit(p', 0)` to the blinded polynomial `p'`. -// 4. Reveals `Cq` and `t = t1 + a.t2` to the verifier. -// The verifier -// 1. Computes the non-hiding commitment `Cp'` as `Cp + a.Cq - t'H = (Cp - t1.H) + a.(Cq - t2.H)`. -// 2. Verifies the opening against `Cp'`. -#[derive(Clone, Debug, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct HidingIpa { - pub ipa_pcs: ipa::IPA, - pub h: C::Affine, -} - -/// `Cp = Commit(p, t1) = (p0.G0 + ... + pn.Gn) + t1.H`. -#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)] -pub struct HidingProof { - /// A hiding commitment to the blinding polynomial `q`, `deg(q) = deg(p), q(z) = 0`. - /// `Commit(q, t2) = (q0.G0 + ... + qn.Gn) + t2.H`. - q: C::Affine, - /// The blinding factor `t` in the hiding commitment `Cp' = Cp + a.Cq` to the blinded polynomial `p' = p + a.q`. - /// `t = t1 + a.t2`, `Cp' = Commit(p', t) = Commit(p', 0) + (t1 + a.t2).H` - t: C::ScalarField, - /// Opening proof for the non-hiding commitment `Commit(p', 0)` to `p'`. - ipa_pcs_proof: ipa_pc::Proof, - // TODO: remove - a: C::ScalarField, -} - -impl> HidingIpa { - pub fn commit_hiding(&self, p: &Poly, t: F) -> Result, ()> { - let c = ipa::IPA::commit(&self.ipa_pcs, p)?; - self.reblind(c.0, F::zero(), t) - } - - pub fn reblind( - &self, - c: C::Affine, - r_old: F, - r_new: F, - ) -> Result, ()> { - let c = c + self.h * (r_new - r_old); - let c = c.into_affine(); - Ok(WrappedAffine(c)) - } -} - -impl CommitterKey for HidingIpa { - fn max_degree(&self) -> usize { - self.ipa_pcs.g.len() - 1 - } -} - -impl VerifierKey for HidingIpa {} - -impl RawVerifierKey for HidingIpa { - type VK = Self; - - fn prepare(&self) -> Self::VK { - self.clone() - } -} - -impl PcsParams for HidingIpa { - type CK = Self; - type VK = Self; - type RVK = Self; - - fn ck(&self) -> Self::CK { - self.clone() - } - - fn vk(&self) -> Self::VK { - self.clone() - } - - fn raw_vk(&self) -> Self::RVK { - self.clone() - } -} - -impl PCS for HidingIpa { - type C = WrappedAffine; - type Proof = HidingProof; - type CK = Self; - type VK = Self; - type Params = Self; - - fn setup(max_degree: usize, rng: &mut R) -> Self::Params { - let ipa_pcs = ipa::IPA::setup(max_degree, rng); - let h = C::Affine::rand(rng); - Self { ipa_pcs, h } - } - - fn commit(ck: &Self::CK, p: &Poly) -> Result { - Self::commit_hiding(ck, p, C::ScalarField::zero()) - } - - fn open( - _ck: &Self::CK, - _p: &Poly, - _x: C::ScalarField, - ) -> Result { - todo!() - } - - fn open_hiding( - ck: &Self::CK, - p: &Poly, - z: C::ScalarField, - t: C::ScalarField, - rng: &mut R, - ) -> Result { - let t1 = t; - let mut q = Poly::rand(p.degree(), rng); - let q_at_z = q.evaluate(&z); - q[0] -= q_at_z; - debug_assert!(q.evaluate(&z).is_zero()); - let t2 = C::ScalarField::rand(rng); - let cq = ck.commit_hiding(&q, t2)?.0; - let a = C::ScalarField::rand(rng); // TODO: that's a FS point - let p = p + q * a; - let t = t1 + t2 * a; - let ipa_pcs_proof = ipa::IPA::open(&ck.ipa_pcs, &p, z)?; - Ok(HidingProof { - q: cq, - t, - ipa_pcs_proof, - a, - }) - } - - fn verify( - vk: &Self::VK, - c: Self::C, - x: C::ScalarField, - z: C::ScalarField, - proof: Self::Proof, - ) -> Result<(), ()> { - let c = c.0 + proof.q * proof.a - vk.h * proof.t; - ipa::IPA::verify( - &vk.ipa_pcs, - WrappedAffine(c.into_affine()), - x, - z, - proof.ipa_pcs_proof, - ) - } -} - -#[cfg(test)] -mod tests { - use crate::ipa_hiding::HidingIpa; - use ark_poly::{DenseUVPolynomial, Polynomial}; - use ark_std::{UniformRand, test_rng}; - use w3f_pcs::Poly; - use w3f_pcs::pcs::PCS; - - #[test] - fn test_hiding_ipa_opening() { - let rng = &mut test_rng(); - - let max_coeffs = 2usize.pow(6); - let max_degree = max_coeffs - 1; - - let hiding_pcs = HidingIpa::::setup(max_coeffs - 1, rng); - - let p = Poly::rand(max_degree, rng); - let t = ark_pallas::Fr::rand(rng); - - let c = hiding_pcs.commit_hiding(&p, t).unwrap(); - - let z = ark_pallas::Fr::rand(rng); - let v = p.evaluate(&z); - let pi = - HidingIpa::::open_hiding(&hiding_pcs, &p, z, t, rng).unwrap(); - - assert!(HidingIpa::::verify(&hiding_pcs, c, z, v, pi).is_ok()); - } -} diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index f7c989f..a6f1645 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -1,9 +1,10 @@ mod prover; mod verifier; -use crate::ipa_hiding::HidingIpa; + use crate::Coeffs; -use ark_ec::{CurveGroup, PrimeGroup}; +use ark_ec::CurveGroup; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PCS; use w3f_pcs::shplonk::AggregateProof; use w3f_plonk_common::PiopProof; diff --git a/pasta-tree/src/level/prover.rs b/pasta-tree/src/level/prover.rs index 60bb142..36d753c 100644 --- a/pasta-tree/src/level/prover.rs +++ b/pasta-tree/src/level/prover.rs @@ -1,5 +1,4 @@ use crate::auth_path::node::LevelWitnessWithBlinding; -use crate::ipa_hiding::HidingIpa; use crate::level::LevelProof; use crate::{Coeffs, CycleSideParams, IPACommitment}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; @@ -8,10 +7,9 @@ use ark_poly::Polynomial; use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, UniformRand}; use std::collections::BTreeSet; -use ark_ff::PrimeField; -use ark_std::iterable::Iterable; -use w3f_pcs::aggregation::multiple::{MultipointClaim, Transcript}; -use w3f_pcs::pcs::{PcsParams, PCS}; +use ark_ff::Zero; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; +use w3f_pcs::pcs::PcsParams; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; @@ -51,6 +49,8 @@ impl> = coord_vecs .iter() @@ -64,12 +64,13 @@ impl>::open_many( + let pcs_opening_proof = Shplonk::>::open_many_hiding( &self.pcs_params, &polys, + &bfs, &coord_sets, - witness.parent_bf, &mut todo.clone(), + rng, ); end_timer!(t_open); diff --git a/pasta-tree/src/level/verifier.rs b/pasta-tree/src/level/verifier.rs index 49bc825..a8b794d 100644 --- a/pasta-tree/src/level/verifier.rs +++ b/pasta-tree/src/level/verifier.rs @@ -1,9 +1,9 @@ -use crate::ipa_hiding::HidingIpa; use crate::level::LevelProof; use crate::{CycleSideParams, IPACommitment}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; use ark_std::{end_timer, start_timer}; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PcsParams; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::VerifierPiop; diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 7f80ea4..58b1dfb 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,12 +1,13 @@ #![feature(bool_to_result)] -use crate::ipa_hiding::HidingIpa; + use ark_ec::{AffineRepr, CurveGroup, PrimeGroup}; use ark_ff::{PrimeField, Zero}; use ark_std::rand::Rng; use std::marker::PhantomData; -use w3f_pcs::aggregation::multiple::Transcript; -use w3f_pcs::pcs::kzg::commitment::WrappedAffine; +use w3f_pcs::aggregation::multiple::ShplonkTranscript; +use w3f_pcs::pcs::commitment::WrappedAffine; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::PCS; use w3f_pcs::shplonk::AggregateProof; @@ -15,9 +16,7 @@ use w3f_plonk_common::PiopProof; use w3f_ring_proof::piop::{FixedColumns, RingCommitments, RingEvaluations}; use w3f_ring_proof::{FixedColumnsCommitted, PiopParams, VerifierKey}; - pub mod auth_path; -pub mod ipa_hiding; pub mod level; pub mod prover; pub mod verifier; @@ -39,7 +38,7 @@ struct CycleParams< #[derive(Clone)] pub struct CycleSideProof> { - piop_proofs: Vec, RingCommitments>, RingEvaluations>>, + piop_proofs: Vec, RingCommitments>, RingEvaluations>>, pcs_proof: AggregateProof>, todo: Coeffs, fixed_columns_committed: Vec>>, @@ -190,7 +189,7 @@ enum CycleSide { #[derive(Clone)] pub struct Coeffs(F, F); -impl> Transcript for Coeffs { +impl> ShplonkTranscript for Coeffs { fn get_gamma(&mut self) -> F { self.0 } @@ -221,7 +220,7 @@ mod tests { use std::collections::BTreeSet; use ark_vesta::VestaConfig; use w3f_pcs::pcs::ipa::IPA; - use w3f_pcs::pcs::kzg::commitment::WrappedAffine; + use w3f_pcs::pcs::commitment::WrappedAffine; use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::{RawVerifierKey, PCS}; use w3f_pcs::shplonk::Shplonk; @@ -239,7 +238,7 @@ mod tests { use w3f_plonk_common::domain::Domain; type PallasIPA = IPA; - type PallasC = WrappedAffine; + type PallasC = WrappedAffine; fn random_witness, R: Rng>( @@ -380,7 +379,6 @@ mod tests { let valid = params.verify(auth_path, proof, wrapped_root); end_timer!(t_verify); assert!(valid); - } // cargo test test_proof --release --features="print-trace" -- --show-output @@ -524,7 +522,7 @@ mod tests { &pcs_ck, &polys, &coord_sets, - ark_pallas::Fr::zero(), + // ark_pallas::Fr::zero(), transcript, ); end_timer!(t_open); diff --git a/pasta-tree/src/prover.rs b/pasta-tree/src/prover.rs index 102f3b8..0e5bd66 100644 --- a/pasta-tree/src/prover.rs +++ b/pasta-tree/src/prover.rs @@ -1,14 +1,14 @@ use crate::auth_path::blinded::BlindedAuthenticationPath; use crate::auth_path::node::LevelWitnessWithBlinding; use crate::auth_path::path::AuthenticationPath; -use crate::ipa_hiding::HidingIpa; use crate::{Coeffs, CurveTreeProof, CycleParams, CycleSideParams, CycleSideProof, IPACommitment}; use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ec::CurveGroup; -use ark_ff::PrimeField; +use ark_ff::{PrimeField, Zero}; use ark_std::rand::Rng; use ark_std::UniformRand; use std::collections::BTreeSet; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PcsParams; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::ProverPiop; @@ -52,6 +52,7 @@ impl, _>::init( self.pcs_params.ck(), @@ -79,16 +80,18 @@ impl>::open_many( + let pcs_proof = Shplonk::>::open_many_hiding( &self.pcs_params, &polys, + &bfs, &coords, - parent_bf, &mut todo.clone(), + rng, ); let proof = CycleSideProof { diff --git a/pasta-tree/src/verifier.rs b/pasta-tree/src/verifier.rs index ad65632..37d438c 100644 --- a/pasta-tree/src/verifier.rs +++ b/pasta-tree/src/verifier.rs @@ -1,9 +1,9 @@ use crate::auth_path::blinded::BlindedAuthenticationPath; -use crate::ipa_hiding::HidingIpa; use crate::{CurveTreeProof, CycleParams, CycleSide, CycleSideParams, CycleSideProof}; use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ec::CurveGroup; use ark_ff::PrimeField; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PcsParams; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::verifier::{PcsOpeningAt2Points, PlonkVerifier}; From 0b0cb283ac4ab04c79a35e0032d00c09068f95b2 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Wed, 20 May 2026 08:58:38 +0300 Subject: [PATCH 33/36] test fixed --- w3f-ring-proof/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 4b16b4d..02b3aad 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -142,7 +142,7 @@ mod tests { let ring = Ring::<_, Bls12_381, _>::with_keys(&piop_params, &pks, &ring_builder_key); - let fixed_columns_committed = ring.as_fixed_columns(); + let fixed_columns_committed = FixedColumnsCommitted::from_ring(&ring); assert_eq!( fixed_columns_committed, verifier_key.fixed_columns_committed From 194e1da51808f6a00674a43c7931337c0847a2a9 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Wed, 20 May 2026 08:58:57 +0300 Subject: [PATCH 34/36] back to hiding --- pasta-tree/src/auth_path/node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pasta-tree/src/auth_path/node.rs b/pasta-tree/src/auth_path/node.rs index d6333ff..335e742 100644 --- a/pasta-tree/src/auth_path/node.rs +++ b/pasta-tree/src/auth_path/node.rs @@ -1,9 +1,9 @@ use crate::CycleSideParams; -use crate::ipa_hiding::HidingIpa; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::{PrimeField, Zero}; use ark_std::rand::Rng; use ark_std::UniformRand; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; /// An element of a tree authentication path. A node on the path together with it's sibling. /// `path_node = self.siblings[self.path_node_idx]` is the node on the path. @@ -40,8 +40,8 @@ impl LevelWitness { ) -> LevelWitnessWithBlinding { LevelWitnessWithBlinding { level_witness: self.clone(), - bf: G::ScalarField::zero(), //self_bf, - parent_bf: G::BaseField::zero(), //parent_bf, + bf: self_bf, + parent_bf, } } From 1b1c7eaed9a7a3529e8c428868e832d3b385c60f Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Wed, 20 May 2026 09:02:03 +0300 Subject: [PATCH 35/36] cargo fmt --- pasta-tree/src/auth_path/blinded.rs | 29 ++++++---- pasta-tree/src/auth_path/node.rs | 11 +++- pasta-tree/src/auth_path/path.rs | 9 +-- pasta-tree/src/level/mod.rs | 13 ++--- pasta-tree/src/level/prover.rs | 20 ++++--- pasta-tree/src/level/verifier.rs | 9 ++- pasta-tree/src/lib.rs | 87 +++++++++++++++++------------ pasta-tree/src/prover.rs | 61 +++++++++++++------- pasta-tree/src/verifier.rs | 50 ++++++++++++----- 9 files changed, 180 insertions(+), 109 deletions(-) diff --git a/pasta-tree/src/auth_path/blinded.rs b/pasta-tree/src/auth_path/blinded.rs index ab87f9c..df57c62 100644 --- a/pasta-tree/src/auth_path/blinded.rs +++ b/pasta-tree/src/auth_path/blinded.rs @@ -18,23 +18,32 @@ impl AuthenticationPathWithBlinding where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { pub(crate) fn apply_bfs( &self, params: &CycleParams, ) -> BlindedAuthenticationPath { - let c0_path = self.c0_path.iter() - .map(|c0_level| c0_level.blinded_path_node(¶ms.c0_params.pcs_params).unwrap()) + let c0_path = self + .c0_path + .iter() + .map(|c0_level| { + c0_level + .blinded_path_node(¶ms.c0_params.pcs_params) + .unwrap() + }) .collect(); - let c1_path = self.c1_path.iter() - .map(|c1_level| c1_level.blinded_path_node(¶ms.c1_params.pcs_params).unwrap()) + let c1_path = self + .c1_path + .iter() + .map(|c1_level| { + c1_level + .blinded_path_node(¶ms.c1_params.pcs_params) + .unwrap() + }) .collect(); - BlindedAuthenticationPath { - c0_path, - c1_path, - } + BlindedAuthenticationPath { c0_path, c1_path } } pub(crate) fn compute_root( &self, diff --git a/pasta-tree/src/auth_path/node.rs b/pasta-tree/src/auth_path/node.rs index 335e742..df51a63 100644 --- a/pasta-tree/src/auth_path/node.rs +++ b/pasta-tree/src/auth_path/node.rs @@ -1,8 +1,8 @@ use crate::CycleSideParams; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::{PrimeField, Zero}; -use ark_std::rand::Rng; use ark_std::UniformRand; +use ark_std::rand::Rng; use w3f_pcs::pcs::ipa::hiding::HidingIpa; /// An element of a tree authentication path. A node on the path together with it's sibling. @@ -90,7 +90,11 @@ pub struct LevelWitnessWithBlinding { impl LevelWitnessWithBlinding { pub(crate) fn blinded_path_node(&self, ipa_pcs: &HidingIpa) -> Result { - let blinded_path_node = ipa_pcs.reblind(self.level_witness.path_node(), G::ScalarField::zero(), self.bf)?; + let blinded_path_node = ipa_pcs.reblind( + self.level_witness.path_node(), + G::ScalarField::zero(), + self.bf, + )?; Ok(blinded_path_node.0) } @@ -101,6 +105,7 @@ impl LevelWitnessWithBlinding { where G::BaseField: PrimeField, { - self.level_witness.compute_parent_with_bf(params, self.parent_bf) + self.level_witness + .compute_parent_with_bf(params, self.parent_bf) } } diff --git a/pasta-tree/src/auth_path/path.rs b/pasta-tree/src/auth_path/path.rs index e7dd83d..68a7ab5 100644 --- a/pasta-tree/src/auth_path/path.rs +++ b/pasta-tree/src/auth_path/path.rs @@ -23,8 +23,8 @@ impl AuthenticationPath where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { pub fn with_blinding(&self, rng: &mut R) -> AuthenticationPathWithBlinding { let mut path_0 = Vec::with_capacity(self.c0_path.len()); @@ -96,15 +96,16 @@ where #[cfg(test)] mod tests { use super::*; - use ark_std::{test_rng, UniformRand}; use crate::tests::{random_nodes, random_path}; + use ark_std::{UniformRand, test_rng}; #[test] fn test_auth_path() { let rng = &mut test_rng(); let domain_size = 2usize.pow(9); - let params = CycleParams::::setup(domain_size, rng);; + let params = + CycleParams::::setup(domain_size, rng); let (leaf, path, root) = random_path(¶ms, 2, rng); diff --git a/pasta-tree/src/level/mod.rs b/pasta-tree/src/level/mod.rs index a6f1645..46fd511 100644 --- a/pasta-tree/src/level/mod.rs +++ b/pasta-tree/src/level/mod.rs @@ -1,16 +1,14 @@ mod prover; mod verifier; - use crate::Coeffs; use ark_ec::CurveGroup; -use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PCS; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::shplonk::AggregateProof; use w3f_plonk_common::PiopProof; use w3f_ring_proof::piop::{RingCommitments, RingEvaluations}; - pub struct LevelProof { piop_proof: PiopProof< C::ScalarField, @@ -24,13 +22,13 @@ pub struct LevelProof { #[cfg(test)] mod tests { - use crate::tests::random_nodes; use crate::CycleParams; - use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; + use crate::tests::random_nodes; use ark_ec::CurveGroup; + use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ff::PrimeField; use ark_pallas::PallasConfig; - use ark_std::{end_timer, start_timer, test_rng, UniformRand}; + use ark_std::{UniformRand, end_timer, start_timer, test_rng}; use ark_vesta::VestaConfig; fn _test_level_proof() @@ -69,7 +67,8 @@ mod tests { let capacity = c1_params.piop_params.keyset_part_size; - let (_, l2_vk) = c1_params.commit_children(l2_nodes.siblings.as_slice(), l1_nodes_with_bf.bf); + let (_, l2_vk) = + c1_params.commit_children(l2_nodes.siblings.as_slice(), l1_nodes_with_bf.bf); let l1_node_fc = l2_vk.fixed_columns_committed; assert_eq!(l1_node_fc.points[0].0, l1_node_blinded); diff --git a/pasta-tree/src/level/prover.rs b/pasta-tree/src/level/prover.rs index 36d753c..05c1b13 100644 --- a/pasta-tree/src/level/prover.rs +++ b/pasta-tree/src/level/prover.rs @@ -1,25 +1,24 @@ use crate::auth_path::node::LevelWitnessWithBlinding; use crate::level::LevelProof; use crate::{Coeffs, CycleSideParams, IPACommitment}; -use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::CurveGroup; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ff::Zero; use ark_poly::Polynomial; use ark_std::rand::Rng; -use ark_std::{end_timer, start_timer, UniformRand}; +use ark_std::{UniformRand, end_timer, start_timer}; use std::collections::BTreeSet; -use ark_ff::Zero; -use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PcsParams; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; -use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ArkTranscript; +use w3f_ring_proof::piop::prover::PiopProver; impl> CycleSideParams> { - pub fn prove_level( &self, witness: &LevelWitnessWithBlinding>, @@ -27,7 +26,12 @@ impl (Affine, LevelProof) { let (fixed_columns, verifier_key) = self.commit_children(&witness.level_witness.siblings, witness.parent_bf); - let piop = PiopProver::build(&self.piop_params, fixed_columns, witness.level_witness.path_node_idx, witness.bf); + let piop = PiopProver::build( + &self.piop_params, + fixed_columns, + witness.level_witness.path_node_idx, + witness.bf, + ); let blinded_node = > as ProverPiop< C::ScalarField, IPACommitment, @@ -81,4 +85,4 @@ impl> -CycleSideParams> +impl> + CycleSideParams> { pub fn verify_level( &self, diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index 58b1dfb..f123c25 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -1,18 +1,17 @@ #![feature(bool_to_result)] - use ark_ec::{AffineRepr, CurveGroup, PrimeGroup}; use ark_ff::{PrimeField, Zero}; use ark_std::rand::Rng; use std::marker::PhantomData; use w3f_pcs::aggregation::multiple::ShplonkTranscript; +use w3f_pcs::pcs::PCS; +use w3f_pcs::pcs::PcsParams; use w3f_pcs::pcs::commitment::WrappedAffine; use w3f_pcs::pcs::ipa::hiding::HidingIpa; -use w3f_pcs::pcs::PcsParams; -use w3f_pcs::pcs::PCS; use w3f_pcs::shplonk::AggregateProof; -use w3f_plonk_common::domain::Domain; use w3f_plonk_common::PiopProof; +use w3f_plonk_common::domain::Domain; use w3f_ring_proof::piop::{FixedColumns, RingCommitments, RingEvaluations}; use w3f_ring_proof::{FixedColumnsCommitted, PiopParams, VerifierKey}; @@ -23,29 +22,36 @@ pub mod verifier; type IPACommitment = as PCS<::ScalarField>>::C; -struct CycleSideParams> { +struct CycleSideParams> { pcs_params: HidingIpa, piop_params: PiopParams, } struct CycleParams< C0: CurveGroup, - C1: CurveGroup, + C1: CurveGroup, > { c0_params: CycleSideParams, c1_params: CycleSideParams, } #[derive(Clone)] -pub struct CycleSideProof> { - piop_proofs: Vec, RingCommitments>, RingEvaluations>>, +pub struct CycleSideProof> { + piop_proofs: Vec< + PiopProof, RingCommitments>, RingEvaluations>, + >, pcs_proof: AggregateProof>, todo: Coeffs, fixed_columns_committed: Vec>>, } #[derive(Clone)] -pub struct CurveTreeProof, C1: CurveGroup> { +pub struct CurveTreeProof< + F0: PrimeField, + F1: PrimeField, + C0: CurveGroup, + C1: CurveGroup, +> { c0_proof: CycleSideProof, c1_proof: CycleSideProof, } @@ -54,8 +60,8 @@ impl CycleParams where F0: PrimeField, F1: PrimeField, - C0: CurveGroup, - C1: CurveGroup, + C0: CurveGroup, + C1: CurveGroup, { pub fn setup(domain_size: usize, rng: &mut R) -> Self { let setup_degree = 3 * domain_size; @@ -76,14 +82,18 @@ where } } -fn piop_params, R: Rng>(domain_size: usize, h: G, rng: &mut R) -> PiopParams { +fn piop_params, R: Rng>( + domain_size: usize, + h: G, + rng: &mut R, +) -> PiopParams { let domain = Domain::::new(domain_size, true); let seed = G::rand(rng); let padding = G::rand(rng); PiopParams::setup(domain, h, seed, padding) } -impl> CycleSideParams { +impl> CycleSideParams { pub fn commit_children( &self, children: &[G], @@ -129,7 +139,6 @@ impl> CycleSideParams { // ipa_pcs: HidingIpa, // domain: Radix2EvaluationDomain, @@ -142,7 +151,6 @@ impl> CycleSideParams, // } - // impl CycleSideParams { // fn setup(log_n: u32, rng: &mut R) -> Result { // let n = 2usize.pow(log_n); @@ -204,10 +212,10 @@ impl> ShplonkTranscript for Coeffs { #[cfg(test)] mod tests { use super::*; + use ark_ec::AdditiveGroup; use ark_ec::scalar_mul::glv::GLVConfig; use ark_ec::scalar_mul::wnaf::WnafContext; use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; - use ark_ec::AdditiveGroup; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; use ark_ff::{BigInteger, Field, Zero}; @@ -216,20 +224,20 @@ mod tests { use ark_poly::Polynomial; use ark_std::iterable::Iterable; use ark_std::rand::Rng; - use ark_std::{cfg_iter_mut, end_timer, start_timer, test_rng, UniformRand}; - use std::collections::BTreeSet; + use ark_std::{UniformRand, cfg_iter_mut, end_timer, start_timer, test_rng}; use ark_vesta::VestaConfig; - use w3f_pcs::pcs::ipa::IPA; - use w3f_pcs::pcs::commitment::WrappedAffine; + use std::collections::BTreeSet; + use w3f_pcs::Poly; use w3f_pcs::pcs::PcsParams; - use w3f_pcs::pcs::{RawVerifierKey, PCS}; + use w3f_pcs::pcs::commitment::WrappedAffine; + use w3f_pcs::pcs::ipa::IPA; + use w3f_pcs::pcs::{PCS, RawVerifierKey}; use w3f_pcs::shplonk::Shplonk; - use w3f_pcs::Poly; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; use w3f_plonk_common::test_helpers::random_vec; use w3f_ring_proof::piop::prover::PiopProver; - use w3f_ring_proof::{index, ArkTranscript, PiopParams}; + use w3f_ring_proof::{ArkTranscript, PiopParams, index}; use crate::auth_path::node::LevelWitness; use crate::auth_path::path::AuthenticationPath; @@ -240,8 +248,7 @@ mod tests { type PallasIPA = IPA; type PallasC = WrappedAffine; - - fn random_witness, R: Rng>( + fn random_witness, R: Rng>( params: &CycleSideParams, path_node: G, rng: &mut R, @@ -256,7 +263,7 @@ mod tests { } } - pub fn random_nodes, R: Rng>( + pub fn random_nodes, R: Rng>( params: &CycleSideParams, path_node: G, rng: &mut R, @@ -266,7 +273,19 @@ mod tests { (parent, level_witness) } - pub fn random_path, R: Rng>(params: &CycleParams, length: usize, rng: &mut R) -> (C0::Affine, AuthenticationPath, CycleSide) { + pub fn random_path< + C0: CurveGroup, + C1: CurveGroup, + R: Rng, + >( + params: &CycleParams, + length: usize, + rng: &mut R, + ) -> ( + C0::Affine, + AuthenticationPath, + CycleSide, + ) { let c0_len = (length + 1) / 2; let c1_len = length / 2; debug_assert_eq!(c0_len + c1_len, length); @@ -291,10 +310,7 @@ mod tests { CycleSide::C0(c0_path_node) }; - let path = AuthenticationPath { - c0_path, - c1_path, - }; + let path = AuthenticationPath { c0_path, c1_path }; (leaf, path, root) } @@ -313,8 +329,8 @@ mod tests { where F0: PrimeField, F1: PrimeField, - C0: SWCurveConfig, - C1: SWCurveConfig, + C0: SWCurveConfig, + C1: SWCurveConfig, { let rng = &mut test_rng(); @@ -323,7 +339,7 @@ mod tests { let (leaf, path, wrapped_root) = random_path(¶ms, 4, rng); let root = match wrapped_root { CycleSide::C0(root) => root, - _ => panic!() + _ => panic!(), }; let path_with_bf = path.with_blinding(rng); @@ -363,7 +379,6 @@ mod tests { let (auth_path, proof) = params.prove(path, rng); end_timer!(t_prove); - // assert_eq!(auth_path.c0_path, vec![l4_node_blinded, l2_node_blinded]); // assert_eq!(auth_path.c1_path, vec![l3_node_blinded, l1_node_blinded]); // @@ -466,7 +481,7 @@ mod tests { &constraints, &alphas, ) - .interpolate(); + .interpolate(); let quotient = piop_params .domain .divide_by_vanishing_poly(&agg_constraint_poly); diff --git a/pasta-tree/src/prover.rs b/pasta-tree/src/prover.rs index 0e5bd66..6205468 100644 --- a/pasta-tree/src/prover.rs +++ b/pasta-tree/src/prover.rs @@ -2,44 +2,50 @@ use crate::auth_path::blinded::BlindedAuthenticationPath; use crate::auth_path::node::LevelWitnessWithBlinding; use crate::auth_path::path::AuthenticationPath; use crate::{Coeffs, CurveTreeProof, CycleParams, CycleSideParams, CycleSideProof, IPACommitment}; -use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ec::CurveGroup; +use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ff::{PrimeField, Zero}; -use ark_std::rand::Rng; use ark_std::UniformRand; +use ark_std::rand::Rng; use std::collections::BTreeSet; -use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::pcs::PcsParams; +use w3f_pcs::pcs::ipa::hiding::HidingIpa; use w3f_pcs::shplonk::Shplonk; use w3f_plonk_common::piop::ProverPiop; use w3f_plonk_common::prover::{PcsOpeningAt2Points, PlonkProver}; -use w3f_ring_proof::piop::prover::PiopProver; use w3f_ring_proof::ArkTranscript; +use w3f_ring_proof::piop::prover::PiopProver; impl CycleParams, Projective> where F0: PrimeField, F1: PrimeField, - C0: SWCurveConfig, - C1: SWCurveConfig, + C0: SWCurveConfig, + C1: SWCurveConfig, { - pub fn prove(&self, auth_path: AuthenticationPath, Projective>, rng: &mut R) -> ( + pub fn prove( + &self, + auth_path: AuthenticationPath, Projective>, + rng: &mut R, + ) -> ( BlindedAuthenticationPath, Projective>, - CurveTreeProof, Projective> + CurveTreeProof, Projective>, ) { let auth_path_with_bf = auth_path.with_blinding(rng); let blinded_auth_path = auth_path_with_bf.apply_bfs(&self); let auth_path = blinded_auth_path.clone(); - let c0_proof = self.c0_params.prove_side(blinded_auth_path.c1_path, &auth_path_with_bf.c1_path, rng); - let c1_proof = self.c1_params.prove_side(blinded_auth_path.c0_path, &auth_path_with_bf.c0_path, rng); - (auth_path, CurveTreeProof { - c0_proof, - c1_proof, - }) + let c0_proof = + self.c0_params + .prove_side(blinded_auth_path.c1_path, &auth_path_with_bf.c1_path, rng); + let c1_proof = + self.c1_params + .prove_side(blinded_auth_path.c0_path, &auth_path_with_bf.c0_path, rng); + (auth_path, CurveTreeProof { c0_proof, c1_proof }) } } -impl> CycleSideParams> +impl> + CycleSideParams> { pub fn prove_side( &self, @@ -61,13 +67,23 @@ impl> as ProverPiop>>::result(&piop); + let piop = PiopProver::build( + &self.piop_params, + fixed_columns, + level.level_witness.path_node_idx, + level.bf, + ); + let blinded_node_ = > as ProverPiop< + C::ScalarField, + IPACommitment, + >>::result(&piop); debug_assert_eq!(blinded_node_, blinded_node); - let (pcs_openings, piop_proof, mut transcript) = plonk_prover.reduce_to_pcs_opening(piop); + let (pcs_openings, piop_proof, mut transcript) = + plonk_prover.reduce_to_pcs_opening(piop); piop_proofs.push(piop_proof); let PcsOpeningAt2Points { polys_at_zeta, @@ -78,7 +94,10 @@ impl CycleParams, Projective> where F0: PrimeField, F1: PrimeField, - C0: SWCurveConfig, - C1: SWCurveConfig, + C0: SWCurveConfig, + C1: SWCurveConfig, { - pub fn verify(&self, auth_path: BlindedAuthenticationPath, Projective>, - proof: CurveTreeProof, Projective>, - root: CycleSide, Affine>) -> bool { + pub fn verify( + &self, + auth_path: BlindedAuthenticationPath, Projective>, + proof: CurveTreeProof, Projective>, + root: CycleSide, Affine>, + ) -> bool { // println!("leaf = {}", auth_path.c0_path[0]); // println!("root = {:?}", root); - let c0_x_coords: Vec> = proof.c0_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); - let c1_x_coords: Vec> = proof.c1_proof.fixed_columns_committed.iter().map(|c| c.points[0].0).collect(); + let c0_x_coords: Vec> = proof + .c0_proof + .fixed_columns_committed + .iter() + .map(|c| c.points[0].0) + .collect(); + let c1_x_coords: Vec> = proof + .c1_proof + .fixed_columns_committed + .iter() + .map(|c| c.points[0].0) + .collect(); // match root { // CycleSide::C0(c0_root) => { // assert_eq!(c0_root, c0_x_coords[c0_x_coords.len() - 1]); @@ -36,15 +49,20 @@ where // assert_eq!(auth_path.c0_path[1..], c0_x_coords); // } // } - let c0_proof = self.c0_params.verify_side(auth_path.c1_path, proof.c0_proof); + let c0_proof = self + .c0_params + .verify_side(auth_path.c1_path, proof.c0_proof); assert!(c0_proof); - let c1_proof = self.c1_params.verify_side(auth_path.c0_path, proof.c1_proof); + let c1_proof = self + .c1_params + .verify_side(auth_path.c0_path, proof.c1_proof); assert!(c1_proof); c0_proof && c1_proof } } -impl> CycleSideParams> +impl> + CycleSideParams> { pub fn verify_side( &self, @@ -61,9 +79,11 @@ impl Date: Wed, 20 May 2026 09:03:25 +0300 Subject: [PATCH 36/36] depends on fflonk/ipa-pcs --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec0d0a2..0baec55 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/", 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 }