diff --git a/w3f-plonk-common/src/gadgets/column_sum.rs b/w3f-plonk-common/src/gadgets/column_sum.rs new file mode 100644 index 0000000..8bda561 --- /dev/null +++ b/w3f-plonk-common/src/gadgets/column_sum.rs @@ -0,0 +1,136 @@ +use ark_ff::{FftField, Field}; +use ark_poly::univariate::DensePolynomial; +use ark_poly::{Evaluations, GeneralEvaluationDomain}; +use ark_std::rc::Rc; +use ark_std::{vec, vec::Vec}; + +use crate::domain::Domain; +use crate::gadgets::{ProverGadget, VerifierGadget}; +use crate::{Column, FieldColumn}; + +/// Computes the sum of the elements of a `col`. All but last. +/// +/// Let `c` be the domain "capacity" (`c = domain.size - ZK_ROWS`). +/// The gadget populates and constrains a witness column `acc`, +/// such that `acc[i+1] = acc[i] + col[i], i = 0,...,c-2`. +/// Then `acc[c-1] = acc[0] + (col[0] + ... + col[c-2]) = acc[0] + sum(col[0..c-1])`. +/// `acc[0]` and `acc[c-1]` have to be additionally constrained. +pub struct ColumnSumPolys { + /// Input column. + /// Should have length `c-1`, + /// `col[0], ..., col[c-2]` + pub col: Rc>, + /// Partial sums of `col`: + /// `acc[0] = 0, acc[i+1] = col[0] + ... + col[i], i = 0,...,c-2` + pub acc: Rc>, + /// `p(X) = X - w^(c-1)` -- disables the constraint for `i = c-1`, i.e. between `acc[c-1]` and `acc[c]`. + pub not_last: FieldColumn, +} + +pub struct ColumnSumEvals { + pub col: F, + pub acc: F, + pub not_last: F, +} + +impl ColumnSumPolys { + pub fn init(col: Rc>, domain: &Domain) -> Self { + assert_eq!(col.len, domain.capacity - 1); // last element is not constrained + let partial_sums = Self::partial_sums(col.vals()); + let mut acc = vec![F::zero()]; + acc.extend(partial_sums); + let acc = domain.private_column(acc); + let acc = Rc::new(acc); + Self { + col, + acc, + not_last: domain.not_last_row.clone(), + } + } + + /// Returns `col[0], col[0] + col[1], ..., col[0] + col[1] + ... + col[n-1]`. + pub fn partial_sums(col: &[F]) -> Vec { + col.iter() + .scan(F::zero(), |state, &x| { + *state += x; + Some(*state) + }) + .collect() + } +} + +impl ProverGadget for ColumnSumPolys { + fn witness_columns(&self) -> Vec> { + vec![self.acc.poly.clone()] + } + + fn constraints(&self) -> Vec> { + // A degree `n` polynomial is computed using evaluations at `4n` points. + // Still it's convenient, as we aggregate the constraints in the evaluation form + // over the `4x` domain. + let col = &self.col.evals_4x; + let acc = &self.acc.evals_4x; + let acc_shifted = &self.acc.shifted_4x(); + let not_last = &self.not_last.evals_4x; + let c = &(&(acc_shifted - acc) - col) * not_last; + vec![c] + } + + fn constraints_linearized(&self, z: &F) -> Vec> { + let c = &self.acc.poly * self.not_last.evaluate(z); + vec![c] + } + + fn domain(&self) -> GeneralEvaluationDomain { + self.col.evals.domain() + } +} + +impl VerifierGadget for ColumnSumEvals { + fn evaluate_constraints_main(&self) -> Vec { + let c = (-self.acc - self.col) * self.not_last; + vec![c] + } +} + +#[cfg(test)] +mod tests { + use ark_ed_on_bls12_381_bandersnatch::Fq; + use ark_ff::Zero; + use ark_poly::Polynomial; + use ark_std::test_rng; + + use crate::domain::Domain; + use crate::test_helpers::random_vec; + + use super::*; + + fn _column_sum_gadget(hiding: bool) { + let rng = &mut test_rng(); + + let log_n = 10; + let n = 2usize.pow(log_n); + let domain = Domain::new(n, hiding); + + let col = random_vec(domain.capacity - 1, rng); + let sum = col.iter().sum(); + let col = Rc::new(domain.private_column(col)); + + let gadget = ColumnSumPolys::::init(col, &domain); + + let acc = &gadget.acc.evals.evals; + assert!(acc[0].is_zero()); + assert_eq!(acc[domain.capacity - 1], sum); + + let constraint_poly = gadget.constraints()[0].interpolate_by_ref(); + + assert_eq!(constraint_poly.degree(), n); + domain.divide_by_vanishing_poly(&constraint_poly); + } + + #[test] + fn column_sum_gadget() { + _column_sum_gadget(false); + _column_sum_gadget(true); + } +} diff --git a/w3f-plonk-common/src/gadgets/ec/mod.rs b/w3f-plonk-common/src/gadgets/ec/mod.rs index 11e9fee..88ef9ff 100644 --- a/w3f-plonk-common/src/gadgets/ec/mod.rs +++ b/w3f-plonk-common/src/gadgets/ec/mod.rs @@ -74,7 +74,7 @@ where domain: &Domain, ) -> Self { assert_eq!(bitmask.bits.len(), domain.capacity - 1); - assert_eq!(points.points.len(), domain.capacity - 1); + // assert_eq!(points.points.len(), domain.capacity - 1); //TODO let not_last = domain.not_last_row.clone(); let acc = bitmask .bits diff --git a/w3f-plonk-common/src/gadgets/fixed_cells.rs b/w3f-plonk-common/src/gadgets/fixed_cells.rs index a08c2c9..4d646f6 100644 --- a/w3f-plonk-common/src/gadgets/fixed_cells.rs +++ b/w3f-plonk-common/src/gadgets/fixed_cells.rs @@ -10,8 +10,6 @@ use crate::{const_evals, Column, FieldColumn}; pub struct FixedCells { col: Rc>, - col_first: F, - col_last: F, l_first: FieldColumn, l_last: FieldColumn, } @@ -27,40 +25,49 @@ pub struct FixedCellsValues { impl FixedCells { pub fn init(col: Rc>, domain: &Domain) -> Self { assert_eq!(col.len, domain.capacity); - let col_first = col.evals.evals[0]; - let col_last = col.evals.evals[domain.capacity - 1]; let l_first = domain.l_first.clone(); let l_last = domain.l_last.clone(); Self { col, - col_first, - col_last, l_first, l_last, } } pub fn constraints(&self) -> Vec> { - let col = &self.col; - let domain = col.domain_4x(); - let first = &const_evals(self.col_first, domain); - let last = &const_evals(self.col_last, domain); - let col = &self.col.evals_4x; - let l_first = &self.l_first.evals_4x; - let l_last = &self.l_last.evals_4x; - let c = &(l_first * &(col - first)) + &(l_last * &(col - last)); + let domain_capacity = self.col.len; // that's an ugly way to learn the capacity, but we've asserted it above. + let c = &Self::constraint_cell(&self.col, &self.l_first, 0) + + &Self::constraint_cell(&self.col, &self.l_last, domain_capacity - 1); vec![c] } pub fn constraints_linearized(&self, _z: &F) -> Vec> { vec![DensePolynomial::zero()] } + + /// Constraints the column `col` to have the value `col[i]` at index `i`. + /// `li` should be the `i-th` Lagrange basis polynomial `li = L_i(X)`. + /// The constraint polynomial is `c(X) = L_i(X).col(X) - col[i].L_i(X)`. + pub fn constraint_cell(col: &FieldColumn, li: &FieldColumn, i: usize) -> Evaluations { + let cell_val = col.evals[i]; + let domain = col.domain_4x(); + let cell_val = &const_evals(cell_val, domain); + let col = &col.evals_4x; + let li = &li.evals_4x; + li * &(col - cell_val) + } +} + +impl FixedCellsValues { + pub fn evaluate_for_cell(col_eval: F, li_eval: F, cell_val: F) -> F { + li_eval * (col_eval - cell_val) + } } impl VerifierGadget for FixedCellsValues { fn evaluate_constraints_main(&self) -> Vec { - let c = - (self.col - self.col_first) * self.l_first + (self.col - self.col_last) * self.l_last; + let c = Self::evaluate_for_cell(self.col, self.l_first, self.col_first) + + Self::evaluate_for_cell(self.col, self.l_last, self.col_last); vec![c] } } diff --git a/w3f-plonk-common/src/gadgets/mod.rs b/w3f-plonk-common/src/gadgets/mod.rs index efb21a3..9d8bdf2 100644 --- a/w3f-plonk-common/src/gadgets/mod.rs +++ b/w3f-plonk-common/src/gadgets/mod.rs @@ -5,6 +5,7 @@ use ark_std::vec::Vec; pub mod booleanity; // pub mod inner_prod_pub; +pub mod column_sum; pub mod ec; pub mod fixed_cells; pub mod inner_prod; diff --git a/w3f-plonk-common/src/lib.rs b/w3f-plonk-common/src/lib.rs index 26ac351..87208d9 100644 --- a/w3f-plonk-common/src/lib.rs +++ b/w3f-plonk-common/src/lib.rs @@ -31,10 +31,10 @@ pub trait Column { #[derive(Clone)] pub struct FieldColumn { // actual (constrained) len of the input in evaluation form - len: usize, - poly: DensePolynomial, - evals: Evaluations, - evals_4x: Evaluations, + pub len: usize, + pub poly: DensePolynomial, + pub evals: Evaluations, + pub evals_4x: Evaluations, } impl FieldColumn { diff --git a/w3f-plonk-common/src/prover.rs b/w3f-plonk-common/src/prover.rs index 2eff75f..6dc96be 100644 --- a/w3f-plonk-common/src/prover.rs +++ b/w3f-plonk-common/src/prover.rs @@ -68,8 +68,6 @@ impl, T: PlonkTranscript> PlonkProver let lin_at_zeta_omega = lin.evaluate(&zeta_omega); transcript.add_evaluations(&columns_at_zeta, &lin_at_zeta_omega); - println!("z= {}", zeta); - 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); diff --git a/w3f-ring-proof/src/piop/prover.rs b/w3f-ring-proof/src/piop/prover.rs index 23ac074..3b78890 100644 --- a/w3f-ring-proof/src/piop/prover.rs +++ b/w3f-ring-proof/src/piop/prover.rs @@ -75,6 +75,7 @@ impl> PiopProver { } } + // TODO: move to params? fn bits_column( params: &PiopParams, index_in_keys: usize, diff --git a/w3f-ring-vrf-snark/src/lib.rs b/w3f-ring-vrf-snark/src/lib.rs index a9c5669..1262972 100644 --- a/w3f-ring-vrf-snark/src/lib.rs +++ b/w3f-ring-vrf-snark/src/lib.rs @@ -14,11 +14,11 @@ pub use w3f_pcs::pcs; pub use w3f_plonk_common::domain::Domain; mod piop; -mod ring_vrf; pub mod ring_vrf_prover; pub mod ring_vrf_verifier; -pub type RingProof = Proof>::C>, RingEvaluations>; +pub type RingVrfProof = + Proof>::C>, RingEvaluations>; #[derive(Clone)] pub struct ArkTranscript(ark_transcript::Transcript); @@ -53,77 +53,75 @@ mod tests { use ark_std::rand::Rng; use ark_std::{end_timer, start_timer, test_rng, UniformRand}; use w3f_pcs::pcs::kzg::KZG; - use w3f_plonk_common::test_helpers::random_vec; - use crate::piop::FixedColumnsCommitted; - use crate::ring_vrf::{Ring, RingBuilderKey}; - use crate::ring_vrf_prover::RingProver; - use crate::ring_vrf_verifier::RingVerifier; + use crate::ring_vrf_prover::RingVrfProver; + use crate::ring_vrf_verifier::RingVrfVerifier; use super::*; - fn _test_ring_proof>(domain_size: usize) { + fn _test_ring_proof>(domain_size: usize, keyset_size: usize) { let rng = &mut test_rng(); let (pcs_params, piop_params) = setup::<_, CS>(rng, domain_size); - 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 k = rng.gen_range(0..keyset_size); // prover's secret index + let mut pks = random_vec::(keyset_size, rng); + let pk_index = rng.gen_range(0..keyset_size); // prover's secret index + let sk = Fr::rand(rng); // prover's secret scalar + let pk = piop_params.g.mul(sk).into_affine(); + pks[pk_index] = pk; let (prover_key, verifier_key) = index::<_, CS, _>(&pcs_params, &piop_params, &pks); - // PROOF generation - let secret = Fr::rand(rng); // prover's secret scalar - let vrf_input = EdwardsAffine::rand(rng); - let vrf_output = vrf_input.mul(secret).into_affine(); - let ring_prover = RingProver::init( + let vrf_in = EdwardsAffine::rand(rng); + let vrf_out = vrf_in.mul(sk).into_affine(); + + let ring_prover = RingVrfProver::init( prover_key, piop_params.clone(), - k, + pk_index, + sk, ArkTranscript::new(b"w3f-ring-vrf-snark-test"), ); let t_prove = start_timer!(|| "Prove"); - let (proof, res) = ring_prover.prove(secret, vrf_input); + let (res, proof) = ring_prover.prove(vrf_in); end_timer!(t_prove); - assert_eq!(res, vrf_output); + assert_eq!(res, vrf_out); - let ring_verifier = RingVerifier::init( + let ring_verifier = RingVrfVerifier::init( verifier_key, piop_params, ArkTranscript::new(b"w3f-ring-vrf-snark-test"), ); let t_verify = start_timer!(|| "Verify"); - let res = ring_verifier.verify(proof, vrf_input, vrf_output); + let res = ring_verifier.verify(vrf_in, vrf_out, proof); end_timer!(t_verify); assert!(res); } - #[test] - fn test_lagrangian_commitment() { - let rng = &mut test_rng(); - - let domain_size = 2usize.pow(9); - - let (pcs_params, piop_params) = setup::<_, KZG>(rng, domain_size); - let ring_builder_key = RingBuilderKey::from_srs(&pcs_params, domain_size); - - 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 (_, verifier_key) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks); - - let ring = Ring::<_, Bls12_381, _>::with_keys(&piop_params, &pks, &ring_builder_key); - - let fixed_columns_committed = FixedColumnsCommitted::from_ring(&ring); - assert_eq!( - fixed_columns_committed, - verifier_key.fixed_columns_committed - ); - } + // #[test] + // fn test_lagrangian_commitment() { + // let rng = &mut test_rng(); + // + // let domain_size = 2usize.pow(9); + // + // let (pcs_params, piop_params) = setup::<_, KZG>(rng, domain_size); + // let ring_builder_key = RingBuilderKey::from_srs(&pcs_params, domain_size); + // + // 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 (_, verifier_key) = index::<_, KZG, _>(&pcs_params, &piop_params, &pks); + // + // let ring = Ring::<_, Bls12_381, _>::with_keys(&piop_params, &pks, &ring_builder_key); + // + // let fixed_columns_committed = FixedColumnsCommitted::from_ring(&ring); + // assert_eq!( + // fixed_columns_committed, + // verifier_key.fixed_columns_committed + // ); + // } fn setup>( rng: &mut R, @@ -131,23 +129,22 @@ mod tests { ) -> (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 = EdwardsAffine::rand(rng); let seed = EdwardsAffine::rand(rng); let padding = EdwardsAffine::rand(rng); - let piop_params = PiopParams::setup(domain, h, seed, padding); - + let piop_params = PiopParams::setup(domain, seed, padding); (pcs_params, piop_params) } - // #[test] - // fn test_ring_proof_kzg() { - // _test_ring_proof::>(2usize.pow(10)); - // } + #[test] + fn test_ring_proof_kzg() { + _test_ring_proof::>(2usize.pow(9), 500); + } #[test] fn test_ring_proof_id() { - _test_ring_proof::(2usize.pow(10)); + _test_ring_proof::(2usize.pow(10), 2usize.pow(10) - 4); // no padding + _test_ring_proof::(2usize.pow(9), 253); + _test_ring_proof::(2usize.pow(9), 1); } } diff --git a/w3f-ring-vrf-snark/src/piop/cell_equality.rs b/w3f-ring-vrf-snark/src/piop/cell_equality.rs new file mode 100644 index 0000000..00b9c6e --- /dev/null +++ b/w3f-ring-vrf-snark/src/piop/cell_equality.rs @@ -0,0 +1,52 @@ +use ark_ff::{FftField, Field, Zero}; +use ark_poly::univariate::DensePolynomial; +use ark_poly::Evaluations; +use ark_std::rc::Rc; +use ark_std::{vec, vec::Vec}; + +use w3f_plonk_common::domain::Domain; +use w3f_plonk_common::gadgets::VerifierGadget; +use w3f_plonk_common::FieldColumn; + +pub struct CellEqualityPolys { + a: Rc>, + b: Rc>, + l_last: FieldColumn, +} + +pub struct CellEqualityEvals { + pub a: F, + pub b: F, + pub l_last: F, +} + +impl CellEqualityPolys { + pub fn init(a: Rc>, b: Rc>, domain: &Domain) -> Self { + assert_eq!(a.len, domain.capacity); + assert_eq!(b.len, domain.capacity); + let a_last = a.evals.evals[domain.capacity - 1]; + let b_last = b.evals.evals[domain.capacity - 1]; + assert_eq!(a_last, b_last); + let l_last = domain.l_last.clone(); + Self { a, b, l_last } + } + + pub fn constraints(&self) -> Vec> { + let a = &self.a.evals_4x; + let b = &self.b.evals_4x; + let l_last = &self.l_last.evals_4x; + let c = l_last * &(a - b); + vec![c] + } + + pub fn constraints_linearized(&self, _z: &F) -> Vec> { + vec![DensePolynomial::zero()] + } +} + +impl VerifierGadget for CellEqualityEvals { + fn evaluate_constraints_main(&self) -> Vec { + let c = self.l_last * (self.a - self.b); + vec![c] + } +} diff --git a/w3f-ring-vrf-snark/src/piop/mod.rs b/w3f-ring-vrf-snark/src/piop/mod.rs index b2a206c..ca040cc 100644 --- a/w3f-ring-vrf-snark/src/piop/mod.rs +++ b/w3f-ring-vrf-snark/src/piop/mod.rs @@ -15,20 +15,23 @@ pub(crate) use verifier::PiopVerifier; use w3f_plonk_common::gadgets::ec::AffineColumn; use w3f_plonk_common::{Column, ColumnsCommited, ColumnsEvaluated}; -use crate::ring_vrf::Ring; use crate::PiopParams; +mod cell_equality; pub mod params; mod prover; mod verifier; #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct RingCommitments> { - // doublings_of_g are prepended by the verifier + // `pks` and `doublings_of_g` are prepended by the verifier pub(crate) sk_bits: C, + pub(crate) pk_index: C, pub(crate) pk_from_sk: [C; 2], pub(crate) doublings_of_in: [C; 2], pub(crate) out_from_in: [C; 2], + pub(crate) pk_from_index: [C; 2], + pub(crate) pk_index_sum: C, pub(crate) phantom: PhantomData, } @@ -36,37 +39,51 @@ impl> ColumnsCommited for RingCommitments< fn to_vec(self) -> Vec { vec![ self.sk_bits, + self.pk_index, self.pk_from_sk[0].clone(), self.pk_from_sk[1].clone(), self.doublings_of_in[0].clone(), self.doublings_of_in[1].clone(), self.out_from_in[0].clone(), self.out_from_in[1].clone(), + self.pk_from_index[0].clone(), + self.pk_from_index[1].clone(), + self.pk_index_sum.clone(), ] } } #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct RingEvaluations { + pub(crate) pks: [F; 2], pub(crate) doublings_of_g: [F; 2], pub(crate) sk_bits: F, + pub(crate) pk_index: F, pub(crate) pk_from_sk: [F; 2], pub(crate) doublings_of_in: [F; 2], pub(crate) out_from_in: [F; 2], + pub(crate) pk_from_index: [F; 2], + pub(crate) pk_index_sum: F, } impl ColumnsEvaluated for RingEvaluations { fn to_vec(self) -> Vec { vec![ + self.pks[0], + self.pks[1], self.doublings_of_g[0], self.doublings_of_g[1], self.sk_bits, + self.pk_index, self.pk_from_sk[0], self.pk_from_sk[1], self.doublings_of_in[0], self.doublings_of_in[1], self.out_from_in[0], self.out_from_in[1], + self.pk_from_index[0], + self.pk_from_index[1], + self.pk_index_sum, ] } } @@ -76,12 +93,14 @@ impl ColumnsEvaluated for RingEvaluations { // #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] #[derive(Clone)] pub struct FixedColumns> { + pks: AffineColumn, doublings_of_g: AffineColumn, } // Commitments to the fixed columns (see above). #[derive(Clone, CanonicalSerialize, CanonicalDeserialize, PartialEq, Eq, Debug)] pub struct FixedColumnsCommitted> { + pub pks: [C; 2], pub doublings_of_g: [C; 2], pub phantom: PhantomData, } @@ -89,33 +108,40 @@ pub struct FixedColumnsCommitted> { impl> FixedColumnsCommitted { fn as_vec(&self) -> Vec { vec![ + self.pks[0].clone(), + self.pks[1].clone(), self.doublings_of_g[0].clone(), self.doublings_of_g[1].clone(), ] } } -impl FixedColumnsCommitted> { - pub fn from_ring>( - ring: &Ring, - ) -> Self { - let cx = KzgCommitment(ring.cx); - let cy = KzgCommitment(ring.cy); - Self { - doublings_of_g: [cx, cy], - phantom: Default::default(), - } - } -} +// impl FixedColumnsCommitted> { +// pub fn from_ring>( +// ring: &Ring, +// ) -> Self { +// let cx = KzgCommitment(ring.cx); +// let cy = KzgCommitment(ring.cy); +// Self { +// doublings_of_g: [cx, cy], +// phantom: Default::default(), +// } +// } +// } impl> FixedColumns { fn commit>(&self, ck: &CS::CK) -> FixedColumnsCommitted { - let points = [ + let pks = [ + CS::commit(ck, self.pks.xs.as_poly()).unwrap(), + CS::commit(ck, self.pks.ys.as_poly()).unwrap(), + ]; + let doublings_of_g = [ CS::commit(ck, self.doublings_of_g.xs.as_poly()).unwrap(), CS::commit(ck, self.doublings_of_g.ys.as_poly()).unwrap(), ]; FixedColumnsCommitted { - doublings_of_g: points, + pks, + doublings_of_g, phantom: Default::default(), } } @@ -136,12 +162,12 @@ pub struct VerifierKey> { } impl VerifierKey> { - pub fn from_ring_and_kzg_vk>( - ring: &Ring, - kzg_vk: RawKzgVerifierKey, - ) -> Self { - Self::from_commitment_and_kzg_vk(FixedColumnsCommitted::from_ring(ring), kzg_vk) - } + // pub fn from_ring_and_kzg_vk>( + // ring: &Ring, + // kzg_vk: RawKzgVerifierKey, + // ) -> Self { + // Self::from_commitment_and_kzg_vk(FixedColumnsCommitted::from_ring(ring), kzg_vk) + // } pub fn from_commitment_and_kzg_vk( commitment: FixedColumnsCommitted>, @@ -165,7 +191,7 @@ pub fn index, Curve: TECurveConfig>( ) -> (ProverKey>, VerifierKey) { let pcs_ck = pcs_params.ck(); let pcs_raw_vk = pcs_params.raw_vk(); - let fixed_columns = piop_params.fixed_columns(&keys); + let fixed_columns = piop_params.fixed_columns(keys.to_vec()); //TODO let fixed_columns_committed = fixed_columns.commit::(&pcs_ck); let verifier_key = VerifierKey { pcs_raw_vk: pcs_raw_vk.clone(), diff --git a/w3f-ring-vrf-snark/src/piop/params.rs b/w3f-ring-vrf-snark/src/piop/params.rs index 318ca0d..c275b65 100644 --- a/w3f-ring-vrf-snark/src/piop/params.rs +++ b/w3f-ring-vrf-snark/src/piop/params.rs @@ -1,150 +1,85 @@ use ark_ec::twisted_edwards::{Affine, TECurveConfig}; -use ark_ec::{AdditiveGroup, AffineRepr, CurveGroup}; +use ark_ec::AffineRepr; use ark_ff::{BigInteger, PrimeField}; use ark_std::{vec, vec::Vec}; +use crate::piop::FixedColumns; use w3f_plonk_common::domain::Domain; +use w3f_plonk_common::gadgets::booleanity::BitColumn; +use w3f_plonk_common::gadgets::ec::te_doubling::Doubling; use w3f_plonk_common::gadgets::ec::AffineColumn; -use crate::piop::FixedColumns; - -/// Plonk Interactive Oracle Proofs (PIOP) parameters. #[derive(Clone)] pub struct PiopParams> { - /// Domain over which the piop is represented. + /// The domain over which the piop is represented. pub(crate) domain: Domain, - /// Number of bits used to represent a jubjub scalar. + /// The number of bits required to represent a jubjub scalar (a secret key). pub(crate) scalar_bitlen: usize, - /// Length of the part of the column representing the public keys (including the padding). - pub keyset_part_size: usize, - /// The generator used to compute public keys, `pk=sk.G`. + /// The generator used to compute public keys, `pk = sk.G`. pub(crate) g: Affine, - /// Blinding base point. - pub(crate) h: Affine, - /// Summation base point. + /// The point from which EC summations start. + /// For curves in TE form, should be an odd-order point of an unknown dlog. + /// Then we require: + /// 1. *the proofs of possession are checked for every public key in the ring*, + /// 2. the `padding` is chosen independently of the `seed`, + /// 3. the inputs `vrf_in` are independent of the `seed` + /// to avoid the doublings. pub(crate) seed: Affine, - /// The point used to pad the list of public keys. + /// The point used to pad the list of public keys up to the `domain.capacity - 1`. + /// Should be of an unknown dlog. pub(crate) padding: Affine, } impl> PiopParams { - /// Initialize PIOP parameters. - /// - /// - `domain`: polynomials evaluation domain. - /// - `h`: Blinding base point. - /// - `seed`: Accumulation base point - /// - `padding`: The point used to pad the list of public keys. - /// - /// All points should be of an unknown discrete log. - pub fn setup( - domain: Domain, - h: Affine, - seed: Affine, - padding: Affine, - ) -> Self { + pub fn setup(domain: Domain, seed: Affine, padding: Affine) -> Self { let scalar_bitlen = Curve::ScalarField::MODULUS_BIT_SIZE as usize; - // 1 accounts for the last cells of the points and bits columns that remain unconstrained - let keyset_part_size = domain.capacity - scalar_bitlen - 1; + assert!(scalar_bitlen + 1 <= domain.capacity); // 1 accounts for the seed cells Self { domain, scalar_bitlen, - keyset_part_size, g: Affine::::generator(), - h, seed, padding, } } - pub fn fixed_columns(&self, _keys: &[Affine]) -> FixedColumns> { - let doublings_of_g = self.doublings_of_g(); - FixedColumns { doublings_of_g } + pub fn max_keys(&self) -> usize { + self.domain.capacity - 1 } - fn doublings_of_g(&self) -> AffineColumn> { - let mut doublings_of_g = self.doublings_of(self.g); - doublings_of_g.resize(self.domain.capacity - 1, self.g); //TODO: eh, may be zeros - AffineColumn::public_column(doublings_of_g, &self.domain) - } - - pub fn doublings_of(&self, p: Affine) -> Vec> { - let mut p = p.into_group(); - let mut doublings = Vec::with_capacity(self.domain.capacity); - doublings.push(p); - for _ in 1..self.scalar_bitlen { - p.double_in_place(); - doublings.push(p); + pub fn fixed_columns(&self, pks: Vec>) -> FixedColumns> { + // TODO: doublings_of_g.len() != pks.len() + FixedColumns { + pks: self.pks_col(pks), + doublings_of_g: self.doublings_of_g_col(), } - CurveGroup::normalize_batch(&doublings) } - pub fn points_column(&self, keys: &[Affine]) -> AffineColumn> { - assert!(keys.len() <= self.keyset_part_size); - let padding_len = self.keyset_part_size - keys.len(); - let padding = vec![self.padding; padding_len]; - let points = [keys, &padding, &self.power_of_2_multiples_of_h()].concat(); - assert_eq!(points.len(), self.domain.capacity - 1); - AffineColumn::public_column(points, &self.domain) + fn pks_col(&self, pks: Vec>) -> AffineColumn> { + assert!(pks.len() <= self.max_keys()); + let mut pks = pks; + pks.resize(self.max_keys(), self.padding); + let pks = AffineColumn::public_column(pks, &self.domain); + pks } - pub fn pubkey_points_column(&self, keys: &[Affine]) -> AffineColumn> { - assert!(keys.len() <= self.keyset_part_size); - let padding_len = self.keyset_part_size - keys.len(); - let padding = vec![self.padding; padding_len]; - let points = [keys, &padding].concat(); - assert!(points.len() < self.domain.capacity); //check if it fits the domain. - AffineColumn::public_column(points, &self.domain) + fn doublings_of_g_col(&self) -> AffineColumn> { + let doublings_of_g = Doubling::doublings_of(self.g, &self.domain); + AffineColumn::public_column(doublings_of_g, &self.domain) } - pub fn power_of_2_multiples_of_h(&self) -> Vec> { - let mut h = self.h.into_group(); - let mut multiples = Vec::with_capacity(self.scalar_bitlen); - multiples.push(h); - for _ in 1..self.scalar_bitlen { - h.double_in_place(); - multiples.push(h); - } - CurveGroup::normalize_batch(&multiples) + /// Represents `index` as a binary column. + pub fn pk_index_col(&self, index: usize) -> BitColumn { + assert!(index < self.max_keys()); + let mut col = vec![false; self.max_keys()]; + col[index] = true; + BitColumn::init(col, &self.domain) } - pub fn scalar_part(&self, e: Curve::ScalarField) -> Vec { - let bits_with_trailing_zeroes = e.into_bigint().to_bits_le(); + /// Represents a scalar in binary. + pub fn sk_bits(&self, sk: Curve::ScalarField) -> Vec { + let bits_with_trailing_zeroes = sk.into_bigint().to_bits_le(); let significant_bits = &bits_with_trailing_zeroes[..self.scalar_bitlen]; significant_bits.to_vec() } - - pub fn keyset_part_selector(&self) -> Vec { - [ - vec![F::one(); self.keyset_part_size], - vec![F::zero(); self.scalar_bitlen], - ] - .concat() - } -} - -#[cfg(test)] -mod tests { - use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, EdwardsAffine, Fq, Fr}; - 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; - - use crate::piop::params::PiopParams; - - #[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 domain = Domain::new(1024, false); - - let params = PiopParams::::setup(domain, h, seed, padding); - let t = Fr::rand(rng); - let t_bits = params.scalar_part(t); - let th = cond_sum(&t_bits, ¶ms.power_of_2_multiples_of_h()); - assert_eq!(th, params.h.mul(t)); - } } diff --git a/w3f-ring-vrf-snark/src/piop/prover.rs b/w3f-ring-vrf-snark/src/piop/prover.rs index bf1013b..940773b 100644 --- a/w3f-ring-vrf-snark/src/piop/prover.rs +++ b/w3f-ring-vrf-snark/src/piop/prover.rs @@ -1,9 +1,9 @@ use ark_ec::twisted_edwards::{Affine, TECurveConfig}; -use ark_ff::PrimeField; +use ark_ff::{PrimeField, Zero}; use ark_poly::univariate::DensePolynomial; use ark_poly::Evaluations; +use ark_std::rc::Rc; use ark_std::{vec, vec::Vec}; -use std::rc::Rc; use w3f_pcs::pcs::Commitment; use crate::piop::params::PiopParams; @@ -17,6 +17,8 @@ use w3f_plonk_common::gadgets::fixed_cells::FixedCells; use w3f_plonk_common::gadgets::ProverGadget; use w3f_plonk_common::piop::ProverPiop; +use crate::piop::cell_equality::CellEqualityPolys; +use w3f_plonk_common::gadgets::column_sum::ColumnSumPolys; use w3f_plonk_common::gadgets::ec::te_doubling::Doubling; use w3f_plonk_common::Column; @@ -51,10 +53,20 @@ use w3f_plonk_common::Column; /// | $k$ | $pk_x$ | $pk_y$ | $acc_{pk_x}$ | $acc_{pk_y}$ | $sk$ | $2^iG$x2 | $acc_{sk}$x2 | $2^iH$x2 | $acc_{out}$x2 | /// | -------- | -------- | -------- | -- | - | - | - | - | - | - | /// | signer's index | x of pubkey | y of pubkey | $\sum k_ipk_x$ | $\sum k_ipk_y$ | binary rep of secret key | | $\sum sk_i2^iG$ | | $\sum sk_i2^iH$ | + +/// Verifier's input is: +/// - the `seed` to seed the `pk_from_sk`, `pk_from_index`, and `out_from_in` additions, +/// - `vrf_in` to seed the `doublings_of_in_gadget`, +/// - `vrf_out = sk.vrf_in + seed` -- the result of `out_from_in`, +/// and also the commitments to +/// - the ring -- the list of public keys enrolled, +/// - the doublings `g, 2g, 4g, ...` of the generator `g` (such that `pk = sk.g`). pub struct PiopProver> { domain: Domain, + pks: Rc>>, doublings_of_g: Rc>>, sk_bits: Rc>, + pk_index: Rc>, // gadgets sk_bits_bool: Booleanity, pk_from_sk: CondAdd>, @@ -62,30 +74,43 @@ pub struct PiopProver> { out_from_in: CondAdd>, out_from_in_x: FixedCells, out_from_in_y: FixedCells, + pk_index_bool: Booleanity, + /// The following 2 together guarantee that the single bit is set in `pk_index[0..domain.capacity - 1]`. + /// `pk_index[domain.capacity - 1]` is not constrained. That's ok because the ec addition gadget ignores the last bit. + pk_index_sum: ColumnSumPolys, + pk_index_sum_val: FixedCells, + pk_from_index: CondAdd>, + pks_equal_x: CellEqualityPolys, + pks_equal_y: CellEqualityPolys, } impl> PiopProver { pub fn build( params: &PiopParams, fixed_columns: FixedColumns>, // TODO: rename to AdviceColumns - _signer_index: usize, //TODO + pk_index: usize, sk: Curve::ScalarField, vrf_in: Affine, ) -> Self { let domain = params.domain.clone(); - let doublings_of_g = fixed_columns.doublings_of_g; + let FixedColumns { + pks, + doublings_of_g, + } = fixed_columns; + let pks = Rc::new(pks); let doublings_of_g = Rc::new(doublings_of_g); let sk_bits = { - let mut sk_bits = params.scalar_part(sk); //TODO: return right thing + let mut sk_bits = params.sk_bits(sk); //TODO: return right thing assert!(sk_bits.len() <= domain.capacity - 1); sk_bits.resize(domain.capacity - 1, false); - let sk_bits = BitColumn::init(sk_bits, ¶ms.domain); + let sk_bits = BitColumn::init(sk_bits, &domain); Rc::new(sk_bits) }; - let sk_bits_bool = Booleanity::init(sk_bits.clone()); + let pk_index = Rc::new(params.pk_index_col(pk_index)); + let sk_bits_bool = Booleanity::init(sk_bits.clone()); // `PK_sk := sk.G` let pk_from_sk = CondAdd::init( sk_bits.clone(), @@ -100,16 +125,40 @@ impl> PiopProver { let out_from_in_x = FixedCells::init(out_from_in.acc.xs.clone(), &domain); let out_from_in_y = FixedCells::init(out_from_in.acc.ys.clone(), &domain); + let pk_index_bool = Booleanity::init(pk_index.clone()); + let pk_index_sum = ColumnSumPolys::init(pk_index.col.clone(), &domain); + let pk_index_sum_val = FixedCells::init(pk_index_sum.acc.clone(), &domain); + let pk_from_index = CondAdd::init(pk_index.clone(), pks.clone(), params.seed, &domain); + + let pks_equal_x = CellEqualityPolys::init( + pk_from_index.acc.xs.clone(), + pk_from_sk.acc.xs.clone(), + &domain, + ); + let pks_equal_y = CellEqualityPolys::init( + pk_from_index.acc.ys.clone(), + pk_from_sk.acc.ys.clone(), + &domain, + ); + Self { domain, + pks, doublings_of_g, sk_bits, + pk_index, sk_bits_bool, pk_from_sk, doublings_of_in_gadget, out_from_in, out_from_in_x, out_from_in_y, + pk_index_bool, + pk_index_sum, + pk_index_sum_val, + pk_from_index, + pks_equal_x, + pks_equal_y, } } } @@ -129,6 +178,7 @@ where commit: Fun, ) -> Self::Commitments { let sk_bits = commit(self.sk_bits.as_poly()); + let pk_index = commit(self.pk_index.as_poly()); let pk_from_sk = [ commit(self.pk_from_sk.acc.xs.as_poly()), commit(self.pk_from_sk.acc.ys.as_poly()), @@ -141,11 +191,19 @@ where commit(self.out_from_in.acc.xs.as_poly()), commit(self.out_from_in.acc.ys.as_poly()), ]; + let pk_from_index = [ + commit(self.pk_from_index.acc.xs.as_poly()), + commit(self.pk_from_index.acc.ys.as_poly()), + ]; + let pk_index_sum = commit(self.pk_index_sum.acc.as_poly()); RingCommitments { sk_bits, + pk_index, pk_from_sk, doublings_of_in, out_from_in, + pk_from_index, + pk_index_sum, phantom: Default::default(), } } @@ -154,22 +212,32 @@ where // Self::Evaluations::to_vec() and Self::Commitments::to_vec(). fn columns(&self) -> Vec> { vec![ + self.pks.xs.as_poly().clone(), + self.pks.ys.as_poly().clone(), + self.doublings_of_g.xs.as_poly().clone(), + self.doublings_of_g.ys.as_poly().clone(), self.sk_bits.as_poly().clone(), + self.pk_index.as_poly().clone(), self.pk_from_sk.acc.xs.as_poly().clone(), self.pk_from_sk.acc.ys.as_poly().clone(), self.doublings_of_in_gadget.doublings.xs.as_poly().clone(), self.doublings_of_in_gadget.doublings.ys.as_poly().clone(), self.out_from_in.acc.xs.as_poly().clone(), self.out_from_in.acc.ys.as_poly().clone(), + self.pk_from_index.acc.xs.as_poly().clone(), + self.pk_from_index.acc.ys.as_poly().clone(), + self.pk_index_sum.acc.as_poly().clone(), ] } fn columns_evaluated(&self, zeta: &F) -> RingEvaluations { + let pks = [self.pks.xs.evaluate(zeta), self.pks.ys.evaluate(zeta)]; let doublings_of_g = [ self.doublings_of_g.xs.evaluate(zeta), self.doublings_of_g.ys.evaluate(zeta), ]; let sk_bits = self.sk_bits.evaluate(zeta); + let pk_index = self.pk_index.evaluate(zeta); let pk_from_sk = [ self.pk_from_sk.acc.xs.evaluate(zeta), self.pk_from_sk.acc.ys.evaluate(zeta), @@ -182,23 +250,68 @@ where self.out_from_in.acc.xs.evaluate(zeta), self.out_from_in.acc.ys.evaluate(zeta), ]; + let pk_from_index = [ + self.pk_from_index.acc.xs.evaluate(zeta), + self.pk_from_index.acc.ys.evaluate(zeta), + ]; + let pk_index_unique = self.pk_index_sum.acc.evaluate(zeta); RingEvaluations { + pks, doublings_of_g, sk_bits, + pk_index, pk_from_sk, doublings_of_in, out_from_in, + pk_from_index, + pk_index_sum: pk_index_unique, } } fn constraints(&self) -> Vec> { [ self.sk_bits_bool.constraints(), + self.pk_index_bool.constraints(), self.pk_from_sk.constraints(), self.doublings_of_in_gadget.constraints(), self.out_from_in.constraints(), + self.pk_from_index.constraints(), + self.pk_index_sum.constraints(), + self.pk_index_sum_val.constraints(), self.out_from_in_x.constraints(), self.out_from_in_y.constraints(), + self.pks_equal_x.constraints(), + self.pks_equal_y.constraints(), + vec![FixedCells::constraint_cell( + &self.pk_from_sk.acc.xs, + &self.domain.l_first, + 0, + )], + vec![FixedCells::constraint_cell( + &self.pk_from_sk.acc.ys, + &self.domain.l_first, + 0, + )], + vec![FixedCells::constraint_cell( + &self.pk_from_index.acc.xs, + &self.domain.l_first, + 0, + )], + vec![FixedCells::constraint_cell( + &self.pk_from_index.acc.ys, + &self.domain.l_first, + 0, + )], + vec![FixedCells::constraint_cell( + &self.doublings_of_in_gadget.doublings.xs, + &self.domain.l_first, + 0, + )], + vec![FixedCells::constraint_cell( + &self.doublings_of_in_gadget.doublings.ys, + &self.domain.l_first, + 0, + )], ] .concat() } @@ -206,11 +319,23 @@ where fn constraints_lin(&self, zeta: &F) -> Vec> { [ self.sk_bits_bool.constraints_linearized(zeta), + self.pk_index_bool.constraints_linearized(zeta), self.pk_from_sk.constraints_linearized(zeta), self.doublings_of_in_gadget.constraints_linearized(zeta), self.out_from_in.constraints_linearized(zeta), + self.pk_from_index.constraints_linearized(zeta), + self.pk_index_sum.constraints_linearized(zeta), + self.pk_index_sum_val.constraints_linearized(zeta), self.out_from_in_x.constraints_linearized(zeta), self.out_from_in_y.constraints_linearized(zeta), + self.pks_equal_x.constraints_linearized(zeta), + self.pks_equal_y.constraints_linearized(zeta), + vec![DensePolynomial::zero()], + vec![DensePolynomial::zero()], + vec![DensePolynomial::zero()], + vec![DensePolynomial::zero()], + vec![DensePolynomial::zero()], + vec![DensePolynomial::zero()], ] .concat() } @@ -219,6 +344,7 @@ where &self.domain } + // TODO: full instance fn result(&self) -> Self::Instance { self.out_from_in.result } diff --git a/w3f-ring-vrf-snark/src/piop/verifier.rs b/w3f-ring-vrf-snark/src/piop/verifier.rs index 6a34b81..d478573 100644 --- a/w3f-ring-vrf-snark/src/piop/verifier.rs +++ b/w3f-ring-vrf-snark/src/piop/verifier.rs @@ -6,12 +6,14 @@ use w3f_pcs::pcs::Commitment; use w3f_plonk_common::domain::EvaluatedDomain; use w3f_plonk_common::gadgets::booleanity::BooleanityValues; +use w3f_plonk_common::gadgets::column_sum::ColumnSumEvals; use w3f_plonk_common::gadgets::ec::te_doubling::DoublingValues; use w3f_plonk_common::gadgets::ec::CondAddValues; use w3f_plonk_common::gadgets::fixed_cells::FixedCellsValues; use w3f_plonk_common::gadgets::VerifierGadget; use w3f_plonk_common::piop::VerifierPiop; +use crate::piop::cell_equality::CellEqualityEvals; use crate::piop::{FixedColumnsCommitted, RingCommitments}; use crate::RingEvaluations; @@ -27,6 +29,16 @@ pub struct PiopVerifier, P: AffineRepr, out_from_in_x: FixedCellsValues, out_from_in_y: FixedCellsValues, + pk_index_bool: BooleanityValues, + pk_index_sum: ColumnSumEvals, + pk_index_sum_val: FixedCellsValues, + pk_from_index: CondAddValues, + pks_equal_x: CellEqualityEvals, + pks_equal_y: CellEqualityEvals, + + //TODO: params? + seed: (F, F), + vrf_in: (F, F), } impl, P: AffineRepr> PiopVerifier { @@ -36,7 +48,7 @@ impl, P: AffineRepr> PiopVerifier witness_columns_committed: RingCommitments, all_columns_evaluated: RingEvaluations, seed: (F, F), - _vrf_in: (F, F), //TODO + vrf_in: (F, F), vrf_out: (F, F), ) -> Self { let sk_bits_bool = BooleanityValues { @@ -93,6 +105,44 @@ impl, P: AffineRepr> PiopVerifier l_last: domain_evals.l_last, }; + let pk_index_bool = BooleanityValues { + bits: all_columns_evaluated.pk_index, + }; + let pk_index_sum = ColumnSumEvals { + col: all_columns_evaluated.pk_index, + acc: all_columns_evaluated.pk_index_sum, + not_last: domain_evals.not_last_row, + }; + let pk_index_sum_val = FixedCellsValues { + col: all_columns_evaluated.pk_index_sum, + col_first: F::zero(), + col_last: F::one(), + l_first: domain_evals.l_first, + l_last: domain_evals.l_last, + }; + + let pk_from_index = CondAddValues { + bitmask: all_columns_evaluated.pk_index, + points: (all_columns_evaluated.pks[0], all_columns_evaluated.pks[1]), + not_last: domain_evals.not_last_row, + acc: ( + all_columns_evaluated.pk_from_index[0], + all_columns_evaluated.pk_from_index[1], + ), + _phantom: Default::default(), + }; + + let pks_equal_x = CellEqualityEvals { + a: all_columns_evaluated.pk_from_index[0], + b: all_columns_evaluated.pk_from_sk[0], + l_last: domain_evals.l_last, + }; + let pks_equal_y = CellEqualityEvals { + a: all_columns_evaluated.pk_from_index[1], + b: all_columns_evaluated.pk_from_sk[1], + l_last: domain_evals.l_last, + }; + Self { domain_evals, fixed_columns_committed, @@ -103,6 +153,14 @@ impl, P: AffineRepr> PiopVerifier out_from_in, out_from_in_x, out_from_in_y, + pk_index_bool, + pk_index_sum, + pk_index_sum_val, + pk_from_index, + pks_equal_x, + pks_equal_y, + seed, + vrf_in, } } } @@ -110,8 +168,8 @@ impl, P: AffineRepr> PiopVerifier impl, Jubjub: TECurveConfig> VerifierPiop for PiopVerifier> { - const N_CONSTRAINTS: usize = 9; - const N_COLUMNS: usize = 9; + const N_CONSTRAINTS: usize = 22; + const N_COLUMNS: usize = 15; fn precommitted_columns(&self) -> Vec { self.fixed_columns_committed.as_vec() @@ -120,22 +178,58 @@ impl, Jubjub: TECurveConfig> Veri fn evaluate_constraints_main(&self) -> Vec { [ self.sk_bits_bool.evaluate_constraints_main(), + self.pk_index_bool.evaluate_constraints_main(), self.pk_from_sk.evaluate_constraints_main(), self.doublings_of_in_gadget.evaluate_constraints_main(), self.out_from_in.evaluate_constraints_main(), + self.pk_from_index.evaluate_constraints_main(), + self.pk_index_sum.evaluate_constraints_main(), + self.pk_index_sum_val.evaluate_constraints_main(), self.out_from_in_x.evaluate_constraints_main(), self.out_from_in_y.evaluate_constraints_main(), + self.pks_equal_x.evaluate_constraints_main(), + self.pks_equal_y.evaluate_constraints_main(), + vec![FixedCellsValues::evaluate_for_cell( + self.pk_from_sk.acc.0, + self.domain_evals.l_first, + self.seed.0, + )], + vec![FixedCellsValues::evaluate_for_cell( + self.pk_from_sk.acc.1, + self.domain_evals.l_first, + self.seed.1, + )], + vec![FixedCellsValues::evaluate_for_cell( + self.pk_from_index.acc.0, + self.domain_evals.l_first, + self.seed.0, + )], + vec![FixedCellsValues::evaluate_for_cell( + self.pk_from_index.acc.1, + self.domain_evals.l_first, + self.seed.1, + )], + vec![FixedCellsValues::evaluate_for_cell( + self.doublings_of_in_gadget.doublings.0, + self.domain_evals.l_first, + self.vrf_in.0, + )], + vec![FixedCellsValues::evaluate_for_cell( + self.doublings_of_in_gadget.doublings.1, + self.domain_evals.l_first, + self.vrf_in.1, + )], ] .concat() } - fn constraint_polynomials_linearized_commitments(&self) -> Vec { - let pk_x = &self.witness_columns_committed.pk_from_sk[0]; - let pk_y = &self.witness_columns_committed.pk_from_sk[1]; + fn lin_poly_commitment(&self, agg_coeffs: &[F]) -> C { + let pk_from_sk_x = &self.witness_columns_committed.pk_from_sk[0]; + let pk_from_sk_y = &self.witness_columns_committed.pk_from_sk[1]; let (pk_x_coeff, pk_y_coeff) = self.pk_from_sk.acc_coeffs_1(); - let pk_from_sk_c1_lin = pk_x.mul(pk_x_coeff) + pk_y.mul(pk_y_coeff); + let pk_from_sk_c1_lin = pk_from_sk_x.mul(pk_x_coeff) + pk_from_sk_y.mul(pk_y_coeff); let (pk_x_coeff, pk_y_coeff) = self.pk_from_sk.acc_coeffs_2(); - let pk_from_sk_c2_lin = pk_x.mul(pk_x_coeff) + pk_y.mul(pk_y_coeff); + let pk_from_sk_c2_lin = pk_from_sk_x.mul(pk_x_coeff) + pk_from_sk_y.mul(pk_y_coeff); let doublings_of_in_x = self.witness_columns_committed.doublings_of_in[0].clone(); let doublings_of_in_y = self.witness_columns_committed.doublings_of_in[1].clone(); @@ -150,14 +244,32 @@ impl, Jubjub: TECurveConfig> Veri let (out_x_coeff, out_y_coeff) = self.out_from_in.acc_coeffs_2(); let out_from_in_c2_lin = out_x.mul(out_x_coeff) + out_y.mul(out_y_coeff); - vec![ + let pk_from_index_x = &self.witness_columns_committed.pk_from_index[0]; + let pk_from_index_y = &self.witness_columns_committed.pk_from_index[1]; + let (pk_x_coeff, pk_y_coeff) = self.pk_from_index.acc_coeffs_1(); + let pk_from_index_c1_lin = + pk_from_index_x.mul(pk_x_coeff) + pk_from_index_y.mul(pk_y_coeff); + let (pk_x_coeff, pk_y_coeff) = self.pk_from_index.acc_coeffs_2(); + let pk_from_index_c2_lin = + pk_from_index_x.mul(pk_x_coeff) + pk_from_index_y.mul(pk_y_coeff); + + let pk_index_sum_lin = + (&self.witness_columns_committed.pk_index_sum).mul(self.pk_index_sum.not_last); + + let per_constraint = vec![ pk_from_sk_c1_lin, pk_from_sk_c2_lin, doublings_of_in_lin[0].clone(), doublings_of_in_lin[1].clone(), out_from_in_c1_lin, out_from_in_c2_lin, - ] + pk_from_index_c1_lin, + pk_from_index_c2_lin, + pk_index_sum_lin, + ]; + + // TODO: optimize muls + C::combine(&agg_coeffs[2..11], &per_constraint) //TODO } fn domain_evaluated(&self) -> &EvaluatedDomain { diff --git a/w3f-ring-vrf-snark/src/ring_vrf_prover.rs b/w3f-ring-vrf-snark/src/ring_vrf_prover.rs index f2f3f12..fe14cfb 100644 --- a/w3f-ring-vrf-snark/src/ring_vrf_prover.rs +++ b/w3f-ring-vrf-snark/src/ring_vrf_prover.rs @@ -7,9 +7,9 @@ use w3f_plonk_common::transcript::PlonkTranscript; use crate::piop::params::PiopParams; use crate::piop::{FixedColumns, PiopProver, ProverKey}; -use crate::{ArkTranscript, RingProof}; +use crate::{ArkTranscript, RingVrfProof}; -pub struct RingProver +pub struct RingVrfProver where F: PrimeField, CS: PCS, @@ -18,11 +18,12 @@ where { piop_params: PiopParams, fixed_columns: FixedColumns>, - k: usize, + pk_index: usize, + sk: Curve::ScalarField, plonk_prover: PlonkProver, } -impl RingProver +impl RingVrfProver where F: PrimeField, CS: PCS, @@ -32,7 +33,8 @@ where pub fn init( prover_key: ProverKey>, piop_params: PiopParams, - k: usize, + pk_index: usize, + sk: Curve::ScalarField, empty_transcript: T, ) -> Self { let ProverKey { @@ -46,25 +48,23 @@ where Self { piop_params, fixed_columns, - k, + pk_index, + sk, plonk_prover, } } - pub fn prove( - &self, - t: Curve::ScalarField, - vrf_input: Affine, - ) -> (RingProof, Affine) { + pub fn prove(&self, vrf_in: Affine) -> (Affine, RingVrfProof) { let piop: PiopProver = PiopProver::build( &self.piop_params, self.fixed_columns.clone(), - self.k, - t, - vrf_input, + self.pk_index, + self.sk, + vrf_in, ); - let res = as ProverPiop>::result(&piop); - (self.plonk_prover.prove(piop), res) + let vrf_out = as ProverPiop>::result(&piop); + let proof = self.plonk_prover.prove(piop); + (vrf_out, proof) } pub fn piop_params(&self) -> &PiopParams { diff --git a/w3f-ring-vrf-snark/src/ring_vrf_verifier.rs b/w3f-ring-vrf-snark/src/ring_vrf_verifier.rs index 0d2c65c..e245b92 100644 --- a/w3f-ring-vrf-snark/src/ring_vrf_verifier.rs +++ b/w3f-ring-vrf-snark/src/ring_vrf_verifier.rs @@ -10,9 +10,9 @@ use w3f_plonk_common::verifier::PlonkVerifier; use crate::piop::params::PiopParams; use crate::piop::{FixedColumnsCommitted, PiopVerifier, VerifierKey}; -use crate::{ArkTranscript, RingProof}; +use crate::{ArkTranscript, RingVrfProof}; -pub struct RingVerifier +pub struct RingVrfVerifier where F: PrimeField, CS: PCS, @@ -24,7 +24,7 @@ where plonk_verifier: PlonkVerifier, } -impl RingVerifier +impl RingVrfVerifier where F: PrimeField, CS: PCS, @@ -47,9 +47,9 @@ where pub fn verify( &self, - proof: RingProof, vrf_in: Affine, vrf_out: Affine, + proof: RingVrfProof, ) -> bool { let (challenges, mut rng) = self.plonk_verifier.restore_challenges( &vrf_out, @@ -58,17 +58,16 @@ where PiopVerifier::>::N_COLUMNS + 1, PiopVerifier::>::N_CONSTRAINTS, ); - println!("{:?}", challenges); let seed = self.piop_params.seed; let seed_plus_out = (seed + vrf_out).into_affine(); - let domain_eval = EvaluatedDomain::new( + let domain_evals = EvaluatedDomain::new( self.piop_params.domain.domain(), challenges.zeta, self.piop_params.domain.hiding, ); let piop = PiopVerifier::<_, _, Affine>::init( - domain_eval, + domain_evals, self.fixed_columns_committed.clone(), proof.column_commitments.clone(), proof.columns_at_zeta.clone(),