diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index e882be02..da1a1f93 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -4,15 +4,15 @@ use std::time::Instant; use log::info; use crate::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData, VerifierCircuitData, VerifierOnlyCircuitData}; -use crate::field::fft::lde_multiple; use crate::field::field::Field; use crate::gates::constant::ConstantGate; -use crate::gates::gate::{Gate, GateInstance, GateRef}; +use crate::gates::gate::{GateInstance, GateRef}; use crate::gates::noop::NoopGate; use crate::generator::{CopyGenerator, WitnessGenerator}; use crate::hash::merkle_root_bit_rev_order; +use crate::polynomial::polynomial::PolynomialValues; use crate::target::Target; -use crate::util::{transpose, log2_strict}; +use crate::util::{log2_strict, transpose, transpose_poly_values}; use crate::wire::Wire; pub struct CircuitBuilder { @@ -126,7 +126,7 @@ impl CircuitBuilder { .collect() } - fn constant_vecs(&self) -> Vec> { + fn constant_polys(&self) -> Vec> { let num_constants = self.gate_instances.iter() .map(|gate_inst| gate_inst.constants.len()) .max() @@ -140,11 +140,15 @@ impl CircuitBuilder { padded_constants }) .collect::>(); + transpose(&constants_per_gate) + .into_iter() + .map(PolynomialValues::new) + .collect() } - fn sigma_vecs(&self) -> Vec> { - vec![vec![F::ZERO]] // TODO + fn sigma_vecs(&self) -> Vec> { + vec![PolynomialValues::zero(self.gate_instances.len())] // TODO } /// Builds a "full circuit", with both prover and verifier data. @@ -155,14 +159,14 @@ impl CircuitBuilder { let degree = self.gate_instances.len(); info!("degree after blinding & padding: {}", degree); - let constant_vecs = self.constant_vecs(); - let constant_ldes = lde_multiple(constant_vecs, self.config.rate_bits); - let constant_ldes_t = transpose(&constant_ldes); + let constant_vecs = self.constant_polys(); + let constant_ldes = PolynomialValues::lde_multiple(constant_vecs, self.config.rate_bits); + let constant_ldes_t = transpose_poly_values(constant_ldes); let constants_root = merkle_root_bit_rev_order(constant_ldes_t.clone()); let sigma_vecs = self.sigma_vecs(); - let sigma_ldes = lde_multiple(sigma_vecs, self.config.rate_bits); - let sigmas_root = merkle_root_bit_rev_order(transpose(&sigma_ldes)); + let sigma_ldes = PolynomialValues::lde_multiple(sigma_vecs, self.config.rate_bits); + let sigmas_root = merkle_root_bit_rev_order(transpose_poly_values(sigma_ldes)); let generators = self.get_generators(); let prover_only = ProverOnlyCircuitData { generators, constant_ldes_t }; diff --git a/src/field/batch_inverse.rs b/src/field/batch_inverse.rs deleted file mode 100644 index 0e86f5f5..00000000 --- a/src/field/batch_inverse.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::field::field::Field; - -fn batch_multiplicative_inverse(x: &[F]) -> Vec { - // This is Montgomery's trick. At a high level, we invert the product of the given field - // elements, then derive the individual inverses from that via multiplication. - - let n = x.len(); - if n == 0 { - return Vec::new(); - } - - let mut a = Vec::with_capacity(n); - a.push(x[0]); - for i in 1..n { - a.push(a[i - 1] * x[i]); - } - - let mut a_inv = vec![F::ZERO; n]; - a_inv[n - 1] = a[n - 1].try_inverse().expect("No inverse"); - for i in (0..n - 1).rev() { - a_inv[i] = x[i + 1] * a_inv[i + 1]; - } - - let mut x_inv = Vec::with_capacity(n); - x_inv.push(a_inv[0]); - for i in 1..n { - x_inv.push(a[i - 1] * a_inv[i]); - } - x_inv -} diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index bb2949bf..295c392f 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -48,6 +48,8 @@ impl Field for CrandallField { const TWO: Self = Self(2); const NEG_ONE: Self = Self(P - 1); + const MULTIPLICATIVE_SUBGROUP_GENERATOR: Self = Self(5); // TODO: Double check. + #[inline(always)] fn sq(&self) -> Self { *self * *self diff --git a/src/field/fft.rs b/src/field/fft.rs index 1061e7a7..3274d5a5 100644 --- a/src/field/fft.rs +++ b/src/field/fft.rs @@ -1,5 +1,6 @@ use crate::field::field::Field; use crate::util::{log2_ceil, log2_strict}; +use crate::polynomial::polynomial::{PolynomialValues, PolynomialCoeffs}; /// Permutes `arr` such that each index is mapped to its reverse in binary. fn reverse_index_bits(arr: Vec) -> Vec { @@ -22,7 +23,7 @@ fn reverse_bits(n: usize, num_bits: usize) -> usize { result } -pub struct FftPrecomputation { +pub(crate) struct FftPrecomputation { /// For each layer index i, stores the cyclic subgroup corresponding to the evaluation domain of /// layer i. The indices within these subgroup vectors are bit-reversed. subgroups_rev: Vec>, @@ -34,12 +35,12 @@ impl FftPrecomputation { } } -pub fn fft(coefficients: Vec) -> Vec { - let precomputation = fft_precompute(coefficients.len()); - fft_with_precomputation_power_of_2(coefficients, &precomputation) +pub(crate) fn fft(poly: PolynomialCoeffs) -> PolynomialValues { + let precomputation = fft_precompute(poly.len()); + fft_with_precomputation_power_of_2(poly, &precomputation) } -pub fn fft_precompute(degree: usize) -> FftPrecomputation { +pub(crate) fn fft_precompute(degree: usize) -> FftPrecomputation { let degree_pow = log2_ceil(degree); let mut subgroups_rev = Vec::new(); @@ -53,13 +54,17 @@ pub fn fft_precompute(degree: usize) -> FftPrecomputation { FftPrecomputation { subgroups_rev } } -pub fn ifft_with_precomputation_power_of_2( - points: Vec, +pub(crate) fn ifft_with_precomputation_power_of_2( + poly: PolynomialValues, precomputation: &FftPrecomputation, -) -> Vec { - let n = points.len(); +) -> PolynomialCoeffs { + let n = poly.len(); let n_inv = F::from_canonical_usize(n).try_inverse().unwrap(); - let mut result = fft_with_precomputation_power_of_2(points, precomputation); + + let PolynomialValues { values } = poly; + let PolynomialValues { values: mut result } = fft_with_precomputation_power_of_2( + PolynomialCoeffs { coeffs: values }, + precomputation); // We reverse all values except the first, and divide each by n. result[0] = result[0] * n_inv; @@ -71,26 +76,26 @@ pub fn ifft_with_precomputation_power_of_2( result[i] = result_i; result[j] = result_j; } - result + PolynomialCoeffs { coeffs: result } } -pub fn fft_with_precomputation_power_of_2( - coefficients: Vec, +pub(crate) fn fft_with_precomputation_power_of_2( + poly: PolynomialCoeffs, precomputation: &FftPrecomputation, -) -> Vec { +) -> PolynomialValues { debug_assert_eq!( - coefficients.len(), + poly.len(), precomputation.subgroups_rev.last().unwrap().len(), "Number of coefficients does not match size of subgroup in precomputation" ); - let degree = coefficients.len(); - let half_degree = coefficients.len() >> 1; - let degree_pow = log2_strict(degree); + let half_degree = poly.len() >> 1; + let degree_pow = poly.log_len(); // In the base layer, we're just evaluating "degree 0 polynomials", i.e. the coefficients // themselves. - let mut evaluations = reverse_index_bits(coefficients); + let PolynomialCoeffs { coeffs } = poly; + let mut evaluations = reverse_index_bits(coeffs); for i in 1..=degree_pow { // In layer i, we're evaluating a series of polynomials, each at 2^i points. In practice @@ -118,49 +123,36 @@ pub fn fft_with_precomputation_power_of_2( } // Reorder so that evaluations' indices correspond to (g_0, g_1, g_2, ...) - reverse_index_bits(evaluations) + let values = reverse_index_bits(evaluations); + PolynomialValues { values } } -pub fn coset_fft(coefficients: Vec, shift: F) -> Vec { - let mut points = fft(coefficients); +pub(crate) fn coset_fft(poly: PolynomialCoeffs, shift: F) -> PolynomialValues { + let mut points = fft(poly); let mut shift_exp_i = F::ONE; - for p in points.iter_mut() { + for p in points.values.iter_mut() { *p *= shift_exp_i; shift_exp_i *= shift; } points } -pub fn ifft(points: Vec) -> Vec { - let precomputation = fft_precompute(points.len()); - ifft_with_precomputation_power_of_2(points, &precomputation) +pub(crate) fn ifft(poly: PolynomialValues) -> PolynomialCoeffs { + let precomputation = fft_precompute(poly.len()); + ifft_with_precomputation_power_of_2(poly, &precomputation) } -pub fn coset_ifft(points: Vec, shift: F) -> Vec { +pub(crate) fn coset_ifft(poly: PolynomialValues, shift: F) -> PolynomialCoeffs { let shift_inv = shift.inverse(); let mut shift_inv_exp_i = F::ONE; - let mut coeffs = ifft(points); - for c in coeffs.iter_mut() { + let mut coeffs = ifft(poly); + for c in coeffs.coeffs.iter_mut() { *c *= shift_inv_exp_i; shift_inv_exp_i *= shift_inv; } coeffs } -pub fn lde_multiple(points: Vec>, rate_bits: usize) -> Vec> { - points.into_iter().map(|p| lde(p, rate_bits)).collect() -} - -pub fn lde(points: Vec, rate_bits: usize) -> Vec { - let original_size = points.len(); - let lde_size = original_size << rate_bits; - let mut coeffs = ifft(points); - for _ in 0..(lde_size - original_size) { - coeffs.push(F::ZERO); - } - fft(coeffs) -} - // #[cfg(test)] // mod tests { // use crate::{Bls12377Scalar, fft_precompute, fft_with_precomputation, CrandallField, ifft_with_precomputation_power_of_2}; diff --git a/src/field/field.rs b/src/field/field.rs index 85cdce26..07dd79f8 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -4,7 +4,6 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi /// A finite field with prime order less than 2^64. pub trait Field: 'static + Copy -+ Clone + Eq + Neg + Add @@ -24,6 +23,8 @@ pub trait Field: 'static const TWO: Self; const NEG_ONE: Self; + const MULTIPLICATIVE_SUBGROUP_GENERATOR: Self; + fn sq(&self) -> Self; fn cube(&self) -> Self; @@ -35,6 +36,35 @@ pub trait Field: 'static self.try_inverse().expect("Tried to invert zero") } + fn batch_multiplicative_inverse(x: &[Self]) -> Vec { + // This is Montgomery's trick. At a high level, we invert the product of the given field + // elements, then derive the individual inverses from that via multiplication. + + let n = x.len(); + if n == 0 { + return Vec::new(); + } + + let mut a = Vec::with_capacity(n); + a.push(x[0]); + for i in 1..n { + a.push(a[i - 1] * x[i]); + } + + let mut a_inv = vec![Self::ZERO; n]; + a_inv[n - 1] = a[n - 1].try_inverse().expect("No inverse"); + for i in (0..n - 1).rev() { + a_inv[i] = x[i + 1] * a_inv[i + 1]; + } + + let mut x_inv = Vec::with_capacity(n); + x_inv.push(a_inv[0]); + for i in 1..n { + x_inv.push(a[i - 1] * a_inv[i]); + } + x_inv + } + fn primitive_root_of_unity(n_power: usize) -> Self; fn cyclic_subgroup_known_order(generator: Self, order: usize) -> Vec; diff --git a/src/field/mod.rs b/src/field/mod.rs index 234fa73a..027dd742 100644 --- a/src/field/mod.rs +++ b/src/field/mod.rs @@ -1,4 +1,3 @@ -pub(crate) mod batch_inverse; pub(crate) mod crandall_field; pub(crate) mod field; pub(crate) mod field_search; diff --git a/src/hash.rs b/src/hash.rs index 1b23c0af..73c3681f 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -8,7 +8,7 @@ use rayon::prelude::*; use crate::field::field::Field; use crate::gmimc::{gmimc_compress, gmimc_permute_array}; use crate::proof::Hash; -use crate::util::{reverse_index_bits, transpose, reverse_index_bits_in_place}; +use crate::util::{reverse_index_bits, reverse_index_bits_in_place, transpose}; const RATE: usize = 8; const CAPACITY: usize = 4; diff --git a/src/main.rs b/src/main.rs index 543897cb..6297ec31 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,18 +7,16 @@ use rayon::prelude::*; use field::crandall_field::CrandallField; use field::fft; -use field::fft::fft_precompute; use crate::field::field::Field; -use crate::util::log2_ceil; use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CircuitConfig; use crate::witness::PartialWitness; use env_logger::Env; use crate::gates::gmimc::GMiMCGate; use std::sync::Arc; -use std::convert::TryInto; use crate::gates::constant::ConstantGate; +use crate::polynomial::polynomial::PolynomialCoeffs; mod circuit_builder; mod circuit_data; @@ -29,7 +27,9 @@ mod gadgets; mod gates; mod generator; mod gmimc; +mod hash; mod plonk_common; +mod polynomial; mod proof; mod prover; mod recursive_verifier; @@ -39,7 +39,6 @@ mod util; mod verifier; mod wire; mod witness; -mod hash; // 112 wire polys, 3 Z polys, 4 parts of quotient poly. const PROVER_POLYS: usize = 113 + 3 + 4; @@ -146,10 +145,10 @@ fn bench_fft() { } let start = Instant::now(); - let result = fft::fft(coeffs); + let result = fft::fft(PolynomialCoeffs { coeffs }); let duration = start.elapsed(); println!("FFT took {:?}", duration); - println!("FFT result: {:?}", result[0]); + println!("FFT result: {:?}", result.values[0]); }); println!("FFT overall took {:?}", start.elapsed()); } diff --git a/src/polynomial/division.rs b/src/polynomial/division.rs new file mode 100644 index 00000000..ba24d85e --- /dev/null +++ b/src/polynomial/division.rs @@ -0,0 +1,66 @@ +use crate::field::fft::{fft, ifft}; +use crate::field::field::Field; +use crate::util::{log2_ceil, log2_strict}; +use crate::polynomial::polynomial::PolynomialCoeffs; + +/// Takes a polynomial `a` in coefficient form, and divides it by `Z_H = X^n - 1`. +/// +/// This assumes `Z_H | a`, otherwise result is meaningless. +pub(crate) fn divide_by_z_h(mut a: PolynomialCoeffs, n: usize) -> PolynomialCoeffs { + // TODO: Is this special case needed? + if a.coeffs.iter().all(|p| *p == F::ZERO) { + return a.clone(); + } + + let g = F::MULTIPLICATIVE_SUBGROUP_GENERATOR; + let mut g_pow = F::ONE; + // Multiply the i-th coefficient of `a` by `g^i`. Then `new_a(w^j) = old_a(g.w^j)`. + a.coeffs.iter_mut().for_each(|x| { + *x = (*x) * g_pow; + g_pow = g * g_pow; + }); + + let root = F::primitive_root_of_unity(log2_strict(a.len())); + // Equals to the evaluation of `a` on `{g.w^i}`. + let mut a_eval = fft(a); + // Compute the denominators `1/(g^n.w^(n*i) - 1)` using batch inversion. + let denominator_g = g.exp_usize(n); + let root_n = root.exp_usize(n); + let mut root_pow = F::ONE; + let denominators = (0..a_eval.len()) + .map(|i| { + if i != 0 { + root_pow = root_pow * root_n; + } + denominator_g * root_pow - F::ONE + }) + .collect::>(); + let denominators_inv = F::batch_multiplicative_inverse(&denominators); + // Divide every element of `a_eval` by the corresponding denominator. + // Then, `a_eval` is the evaluation of `a/Z_H` on `{g.w^i}`. + a_eval.values + .iter_mut() + .zip(denominators_inv.iter()) + .for_each(|(x, &d)| { + *x = (*x) * d; + }); + // `p` is the interpolating polynomial of `a_eval` on `{w^i}`. + let mut p = ifft(a_eval); + // We need to scale it by `g^(-i)` to get the interpolating polynomial of `a_eval` on `{g.w^i}`, + // a.k.a `a/Z_H`. + let g_inv = g.inverse(); + let mut g_inv_pow = F::ONE; + p.coeffs.iter_mut().for_each(|x| { + *x = (*x) * g_inv_pow; + g_inv_pow = g_inv_pow * g_inv; + }); + p +} + +#[cfg(test)] +mod tests { + #[test] + fn division_by_z_h() { + // TODO + } +} diff --git a/src/polynomial/mod.rs b/src/polynomial/mod.rs new file mode 100644 index 00000000..1e8fe6ed --- /dev/null +++ b/src/polynomial/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod division; +pub(crate) mod polynomial; diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs new file mode 100644 index 00000000..8853ea3a --- /dev/null +++ b/src/polynomial/polynomial.rs @@ -0,0 +1,96 @@ +use crate::field::field::Field; +use crate::util::log2_strict; +use crate::field::fft::{ifft, fft}; + +/// A polynomial in point-value form. The number of values must be a power of two. +/// +/// The points are implicitly `g^i`, where `g` generates the subgroup whose size equals the number +/// of points. +#[derive(Clone, Debug)] +pub(crate) struct PolynomialValues { + pub(crate) values: Vec, +} + +impl PolynomialValues { + pub(crate) fn new(values: Vec) -> Self { + assert!(values.len().is_power_of_two()); + PolynomialValues { values } + } + + pub(crate) fn zero(len: usize) -> Self { + Self::new(vec![F::ZERO; len]) + } + + /// The number of values stored. + pub(crate) fn len(&self) -> usize { + self.values.len() + } + + pub fn lde_multiple( + polys: Vec, + rate_bits: usize, + ) -> Vec { + polys.into_iter() + .map(|p| p.lde(rate_bits)) + .collect() + } + + pub(crate) fn lde(self, rate_bits: usize) -> Self { + let mut coeffs = ifft(self).lde(rate_bits); + fft(coeffs) + } +} + +/// A polynomial in coefficient form. The number of coefficients must be a power of two. +#[derive(Clone, Debug)] +pub(crate) struct PolynomialCoeffs { + pub(crate) coeffs: Vec, +} + +impl PolynomialCoeffs { + pub(crate) fn new(coeffs: Vec) -> Self { + assert!(coeffs.len().is_power_of_two()); + PolynomialCoeffs { coeffs } + } + + pub(crate) fn zero(len: usize) -> Self { + Self::new(vec![F::ZERO; len]) + } + + /// The number of coefficients. This does not filter out any zero coefficients, so it is not + /// necessarily related to the degree. + pub(crate) fn len(&self) -> usize { + self.coeffs.len() + } + + pub(crate) fn log_len(&self) -> usize { + log2_strict(self.len()) + } + + pub(crate) fn chunks(&self, chunk_size: usize) -> Vec { + assert!(chunk_size.is_power_of_two()); + self.coeffs + .chunks(chunk_size) + .map(|chunk| PolynomialCoeffs::new(chunk.to_vec())) + .collect() + } + + pub fn lde_multiple( + polys: Vec, + rate_bits: usize, + ) -> Vec { + polys.into_iter() + .map(|p| p.lde(rate_bits)) + .collect() + } + + pub(crate) fn lde(mut self, rate_bits: usize) -> Self { + let original_size = self.len(); + let lde_size = original_size << rate_bits; + let Self { mut coeffs } = self; + for _ in 0..(lde_size - original_size) { + coeffs.push(F::ZERO); + } + Self { coeffs } + } +} diff --git a/src/prover.rs b/src/prover.rs index 49a76efb..262eb2c0 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -1,20 +1,21 @@ -use std::env::var; use std::time::Instant; use log::info; use rayon::prelude::*; -use crate::circuit_data::{CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData}; +use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; use crate::constraint_polynomial::EvaluationVars; -use crate::field::fft::{fft, ifft, lde, lde_multiple}; +use crate::field::fft::{fft, ifft}; use crate::field::field::Field; use crate::generator::generate_partial_witness; -use crate::hash::{compress, hash_n_to_hash, hash_n_to_m, hash_or_noop, merkle_root_bit_rev_order}; +use crate::hash::{merkle_root_bit_rev_order}; use crate::plonk_common::reduce_with_powers; -use crate::proof::{Hash, Proof}; -use crate::util::{log2_ceil, reverse_index_bits, transpose}; +use crate::proof::{Proof}; +use crate::util::{transpose, transpose_poly_values}; use crate::wire::Wire; use crate::witness::PartialWitness; +use crate::polynomial::division::divide_by_z_h; +use crate::polynomial::polynomial::{PolynomialValues, PolynomialCoeffs}; pub(crate) fn prove( prover_data: &ProverOnlyCircuitData, @@ -27,6 +28,7 @@ pub(crate) fn prove( generate_partial_witness(&mut witness, &prover_data.generators); info!("Witness generation took {}s", start_witness.elapsed().as_secs_f32()); + let start_proof_gen = Instant::now(); let config = common_data.config; let num_wires = config.num_wires; @@ -41,7 +43,7 @@ pub(crate) fn prove( // TODO: Could try parallelizing the transpose, or not doing it explicitly, instead having // merkle_root_bit_rev_order do it implicitly. let start_wire_transpose = Instant::now(); - let wire_ldes_t = transpose(&wire_ldes); + let wire_ldes_t = transpose_poly_values(wire_ldes); info!("Transposing wire LDEs took {}s", start_wire_transpose.elapsed().as_secs_f32()); // TODO: Could avoid cloning if it's significant? @@ -50,8 +52,8 @@ pub(crate) fn prove( info!("Merklizing wire LDEs took {}s", start_wires_root.elapsed().as_secs_f32()); let plonk_z_vecs = compute_zs(&common_data); - let plonk_z_ldes = lde_multiple(plonk_z_vecs, config.rate_bits); - let plonk_z_ldes_t = transpose(&plonk_z_ldes); + let plonk_z_ldes = PolynomialValues::lde_multiple(plonk_z_vecs, config.rate_bits); + let plonk_z_ldes_t = transpose_poly_values(plonk_z_ldes); let plonk_z_root = merkle_root_bit_rev_order(plonk_z_ldes_t.clone()); let alpha = F::ZERO; // TODO @@ -61,17 +63,21 @@ pub(crate) fn prove( common_data, prover_data, wire_ldes_t, plonk_z_ldes_t, alpha); info!("Computing vanishing poly took {}s", start_vanishing_poly.elapsed().as_secs_f32()); - let div_z_h_start = Instant::now(); - // TODO - info!("Division by Z_H took {}s", div_z_h_start.elapsed().as_secs_f32()); + let quotient_poly_start = Instant::now(); + let vanishing_poly_coeffs = ifft(vanishing_poly); + let plonk_t = divide_by_z_h(vanishing_poly_coeffs, degree); + // Split t into degree-n chunks. + let plonk_t_chunks = plonk_t.chunks(degree); + info!("Computing quotient poly took {}s", quotient_poly_start.elapsed().as_secs_f32()); - let plonk_t: Vec = todo!(); // vanishing_poly / Z_H // Need to convert to coeff form and back? - let plonk_t_parts = todo!(); - let plonk_t_ldes = lde_multiple(plonk_t_parts, config.rate_bits); - let plonk_t_root = merkle_root_bit_rev_order(transpose(&plonk_t_ldes)); + let plonk_t_ldes = PolynomialCoeffs::lde_multiple(plonk_t_chunks, config.rate_bits); + let plonk_t_ldes = plonk_t_ldes.into_iter().map(fft).collect(); + let plonk_t_root = merkle_root_bit_rev_order(transpose_poly_values(plonk_t_ldes)); - let openings = todo!(); + let openings = Vec::new(); // TODO + + info!("Proof generation took {}s", start_proof_gen.elapsed().as_secs_f32()); Proof { wires_root, @@ -81,14 +87,14 @@ pub(crate) fn prove( } } -fn compute_zs(common_data: &CommonCircuitData) -> Vec> { +fn compute_zs(common_data: &CommonCircuitData) -> Vec> { (0..common_data.config.num_checks) .map(|i| compute_z(common_data, i)) .collect() } -fn compute_z(common_data: &CommonCircuitData, i: usize) -> Vec { - vec![F::ZERO; common_data.degree()] // TODO +fn compute_z(common_data: &CommonCircuitData, i: usize) -> PolynomialValues { + PolynomialValues::zero(common_data.degree()) // TODO } fn compute_vanishing_poly( @@ -97,7 +103,7 @@ fn compute_vanishing_poly( wire_ldes_t: Vec>, plonk_z_lde_t: Vec>, alpha: F, -) -> Vec { +) -> PolynomialValues { let lde_size = common_data.lde_size(); let lde_gen = common_data.lde_generator(); @@ -129,7 +135,7 @@ fn compute_vanishing_poly( point *= lde_gen; } debug_assert_eq!(point, F::ONE); - result + PolynomialValues::new(result) } fn compute_vanishing_poly_entry( @@ -150,7 +156,7 @@ fn compute_wire_lde( witness: &PartialWitness, degree: usize, rate_bits: usize, -) -> Vec { +) -> PolynomialValues { let wire_values = (0..degree) // Some gates do not use all wires, and we do not require that generators populate unused // wires, so some wire values will not be set. We can set these to any value; here we @@ -158,5 +164,5 @@ fn compute_wire_lde( // wires, but that isn't trivial. .map(|gate| witness.try_get_wire(Wire { gate, input }).unwrap_or(F::ZERO)) .collect(); - lde(wire_values, rate_bits) + PolynomialValues::new(wire_values).lde(rate_bits) } diff --git a/src/util.rs b/src/util.rs index a6111805..a40c0d9e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,6 @@ +use crate::polynomial::polynomial::PolynomialValues; +use crate::field::field::Field; + pub(crate) fn ceil_div_usize(a: usize, b: usize) -> usize { (a + b - 1) / b } @@ -17,6 +20,13 @@ pub(crate) fn log2_strict(n: usize) -> usize { log2_ceil(n) } +pub(crate) fn transpose_poly_values(polys: Vec>) -> Vec> { + let poly_values = polys.into_iter() + .map(|p| p.values) + .collect::>(); + transpose(&poly_values) +} + pub(crate) fn transpose(matrix: &[Vec]) -> Vec> { let old_rows = matrix.len(); let old_cols = matrix[0].len();