From a6acd14dfaadbb3a742ff8ee8a1d199fd04ffdc0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 16 Jun 2021 17:43:41 +0200 Subject: [PATCH] Minor rewrites and optimizations --- src/circuit_builder.rs | 15 ++++++++------- src/circuit_data.rs | 2 ++ src/field/fft.rs | 13 +++++++------ src/field/field.rs | 14 +++++++------- src/field/lagrange.rs | 7 ++----- src/permutation_argument.rs | 4 ++-- src/prover.rs | 21 ++++++++++++++++++++- 7 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 4150bb68..1916eba6 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -236,7 +236,7 @@ impl, const D: usize> CircuitBuilder { .collect() } - fn sigma_vecs(&self, k_is: &[F]) -> Vec> { + fn sigma_vecs(&self, k_is: &[F], subgroup: &[F]) -> Vec> { let degree = self.gate_instances.len(); let degree_log = log2_strict(degree); let mut target_partitions = TargetPartitions::new(); @@ -256,7 +256,7 @@ impl, const D: usize> CircuitBuilder { } let wire_partitions = target_partitions.to_wire_partitions(); - wire_partitions.get_sigma_polys(degree_log, k_is) + wire_partitions.get_sigma_polys(degree_log, k_is, subgroup) } /// Builds a "full circuit", with both prover and verifier data. @@ -270,6 +270,9 @@ impl, const D: usize> CircuitBuilder { let degree = self.gate_instances.len(); info!("degree after blinding & padding: {}", degree); + let degree_bits = log2_strict(degree); + let subgroup = F::two_adic_subgroup(degree_bits); + let constant_vecs = self.constant_polys(); let constants_commitment = ListPolynomialCommitment::new( constant_vecs.into_iter().map(|v| v.ifft()).collect(), @@ -278,7 +281,7 @@ impl, const D: usize> CircuitBuilder { ); let k_is = get_unique_coset_shifts(degree, self.config.num_routed_wires); - let sigma_vecs = self.sigma_vecs(&k_is); + let sigma_vecs = self.sigma_vecs(&k_is, &subgroup); let sigmas_commitment = ListPolynomialCommitment::new( sigma_vecs.into_iter().map(|v| v.ifft()).collect(), self.config.fri_config.rate_bits, @@ -292,11 +295,11 @@ impl, const D: usize> CircuitBuilder { sigmas_root, }; - let generators = self.generators; let prover_only = ProverOnlyCircuitData { - generators, + generators: self.generators, constants_commitment, sigmas_commitment, + subgroup, }; // The HashSet of gates will have a non-deterministic order. When converting to a Vec, we @@ -310,8 +313,6 @@ impl, const D: usize> CircuitBuilder { .max() .expect("No gates?"); - let degree_bits = log2_strict(degree); - // TODO: This should also include an encoding of gate constraints. let circuit_digest_parts = [constants_root.elements, sigmas_root.elements]; let circuit_digest = hash_n_to_hash(circuit_digest_parts.concat(), false); diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 4d9a7110..6cc38522 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -104,6 +104,8 @@ pub(crate) struct ProverOnlyCircuitData { pub constants_commitment: ListPolynomialCommitment, /// Commitments to the sigma polynomial. pub sigmas_commitment: ListPolynomialCommitment, + /// Subgroup of order `degree`. + pub subgroup: Vec, } /// Circuit data required by the verifier, but not the prover. diff --git a/src/field/fft.rs b/src/field/fft.rs index 8bcde967..abce58d6 100644 --- a/src/field/fft.rs +++ b/src/field/fft.rs @@ -44,12 +44,14 @@ pub(crate) fn fft_precompute(degree: usize) -> FftPrecomputation { let degree_log = log2_ceil(degree); let mut subgroups_rev = Vec::new(); - for i in 0..=degree_log { - let g_i = F::primitive_root_of_unity(i); - let subgroup = F::cyclic_subgroup_known_order(g_i, 1 << i); + let mut subgroup = F::two_adic_subgroup(degree_log); + for _i in 0..=degree_log { + let subsubgroup = subgroup.iter().step_by(2).copied().collect(); let subgroup_rev = reverse_index_bits(subgroup); subgroups_rev.push(subgroup_rev); + subgroup = subsubgroup; } + subgroups_rev.reverse(); FftPrecomputation { subgroups_rev } } @@ -200,10 +202,9 @@ mod tests { let degree = coefficients.len(); let degree_log = log2_strict(degree); - let g = F::primitive_root_of_unity(degree_log); - let powers_of_g = F::cyclic_subgroup_known_order(g, degree); + let subgroup = F::two_adic_subgroup(degree_log); - let values = powers_of_g + let values = subgroup .into_iter() .map(|x| evaluate_at_naive(&coefficients, x)) .collect(); diff --git a/src/field/field.rs b/src/field/field.rs index 3c6f0e47..b637c72b 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -111,13 +111,13 @@ pub trait Field: /// Computes a multiplicative subgroup whose order is known in advance. fn cyclic_subgroup_known_order(generator: Self, order: usize) -> Vec { - let mut subgroup = Vec::with_capacity(order); - let mut current = Self::ONE; - for _i in 0..order { - subgroup.push(current); - current *= generator; - } - subgroup + generator.powers().take(order).collect() + } + + /// Computes the subgroup generated by the root of unity of a given order generated by `Self::primitive_root_of_unity`. + fn two_adic_subgroup(n_log: usize) -> Vec { + let generator = Self::primitive_root_of_unity(n_log); + generator.powers().take(1 << n_log).collect() } fn cyclic_subgroup_unknown_order(generator: Self) -> Vec { diff --git a/src/field/lagrange.rs b/src/field/lagrange.rs index 8911feb0..4b75651b 100644 --- a/src/field/lagrange.rs +++ b/src/field/lagrange.rs @@ -10,10 +10,8 @@ use crate::util::log2_ceil; pub(crate) fn interpolant(points: &[(F, F)]) -> PolynomialCoeffs { let n = points.len(); let n_log = log2_ceil(n); - let n_padded = 1 << n_log; - let g = F::primitive_root_of_unity(n_log); - let subgroup = F::cyclic_subgroup_known_order(g, n_padded); + let subgroup = F::two_adic_subgroup(n_log); let barycentric_weights = barycentric_weights(points); let subgroup_evals = subgroup .into_iter() @@ -92,8 +90,7 @@ mod tests { for deg_log in 0..4 { let deg = 1 << deg_log; - let g = F::primitive_root_of_unity(deg_log); - let domain = F::cyclic_subgroup_known_order(g, deg); + let domain = F::two_adic_subgroup(deg_log); let coeffs = F::rand_vec(deg); let coeffs = PolynomialCoeffs { coeffs }; diff --git a/src/permutation_argument.rs b/src/permutation_argument.rs index 62ee63d4..54436ecb 100644 --- a/src/permutation_argument.rs +++ b/src/permutation_argument.rs @@ -110,9 +110,9 @@ impl WirePartitions { &self, degree_log: usize, k_is: &[F], + subgroup: &[F], ) -> Vec> { let degree = 1 << degree_log; - let subgroup_generator = F::primitive_root_of_unity(degree_log); let sigma = self.get_sigma_map(degree); sigma @@ -120,7 +120,7 @@ impl WirePartitions { .map(|chunk| { let values = chunk .par_iter() - .map(|&x| k_is[x / degree] * subgroup_generator.exp((x % degree) as u64)) + .map(|&x| k_is[x / degree] * subgroup[x % degree]) .collect::>(); PolynomialValues::new(values) }) diff --git a/src/prover.rs b/src/prover.rs index 7a492eaa..0731d2b4 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -157,7 +157,26 @@ fn compute_z, const D: usize>( common_data: &CommonCircuitData, _i: usize, ) -> PolynomialCoeffs { - PolynomialCoeffs::zero(common_data.degree()) // TODO + todo!() + // let subgroup = + // let mut plonk_z_points = vec![F::ONE]; + // let k_is = common_data.k_is; + // for i in 1..common_data.degree() { + // let x = subgroup[i - 1]; + // let mut numerator = F::ONE; + // let mut denominator = F::ONE; + // for j in 0..NUM_ROUTED_WIRES { + // let wire_value = witness.get_indices(i - 1, j); + // let k_i = k_is[j]; + // let s_id = k_i * x; + // let s_sigma = sigma_values[j][8 * (i - 1)]; + // numerator = numerator * (wire_value + beta * s_id + gamma); + // denominator = denominator * (wire_value + beta * s_sigma + gamma); + // } + // let last = *plonk_z_points.last().unwrap(); + // plonk_z_points.push(last * numerator / denominator); + // } + // plonk_z_points } fn compute_vanishing_polys, const D: usize>(