Refactor polynomial code

This commit is contained in:
Daniel Lubarov 2021-03-30 13:30:31 -07:00
parent 07718397ea
commit 6c8dfb97ac
13 changed files with 293 additions and 117 deletions

View File

@ -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<F: Field> {
@ -126,7 +126,7 @@ impl<F: Field> CircuitBuilder<F> {
.collect()
}
fn constant_vecs(&self) -> Vec<Vec<F>> {
fn constant_polys(&self) -> Vec<PolynomialValues<F>> {
let num_constants = self.gate_instances.iter()
.map(|gate_inst| gate_inst.constants.len())
.max()
@ -140,11 +140,15 @@ impl<F: Field> CircuitBuilder<F> {
padded_constants
})
.collect::<Vec<_>>();
transpose(&constants_per_gate)
.into_iter()
.map(PolynomialValues::new)
.collect()
}
fn sigma_vecs(&self) -> Vec<Vec<F>> {
vec![vec![F::ZERO]] // TODO
fn sigma_vecs(&self) -> Vec<PolynomialValues<F>> {
vec![PolynomialValues::zero(self.gate_instances.len())] // TODO
}
/// Builds a "full circuit", with both prover and verifier data.
@ -155,14 +159,14 @@ impl<F: Field> CircuitBuilder<F> {
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 };

View File

@ -1,30 +0,0 @@
use crate::field::field::Field;
fn batch_multiplicative_inverse<F: Field>(x: &[F]) -> Vec<F> {
// 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
}

View File

@ -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

View File

@ -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<T: Copy>(arr: Vec<T>) -> Vec<T> {
@ -22,7 +23,7 @@ fn reverse_bits(n: usize, num_bits: usize) -> usize {
result
}
pub struct FftPrecomputation<F: Field> {
pub(crate) struct FftPrecomputation<F: Field> {
/// 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<Vec<F>>,
@ -34,12 +35,12 @@ impl<F: Field> FftPrecomputation<F> {
}
}
pub fn fft<F: Field>(coefficients: Vec<F>) -> Vec<F> {
let precomputation = fft_precompute(coefficients.len());
fft_with_precomputation_power_of_2(coefficients, &precomputation)
pub(crate) fn fft<F: Field>(poly: PolynomialCoeffs<F>) -> PolynomialValues<F> {
let precomputation = fft_precompute(poly.len());
fft_with_precomputation_power_of_2(poly, &precomputation)
}
pub fn fft_precompute<F: Field>(degree: usize) -> FftPrecomputation<F> {
pub(crate) fn fft_precompute<F: Field>(degree: usize) -> FftPrecomputation<F> {
let degree_pow = log2_ceil(degree);
let mut subgroups_rev = Vec::new();
@ -53,13 +54,17 @@ pub fn fft_precompute<F: Field>(degree: usize) -> FftPrecomputation<F> {
FftPrecomputation { subgroups_rev }
}
pub fn ifft_with_precomputation_power_of_2<F: Field>(
points: Vec<F>,
pub(crate) fn ifft_with_precomputation_power_of_2<F: Field>(
poly: PolynomialValues<F>,
precomputation: &FftPrecomputation<F>,
) -> Vec<F> {
let n = points.len();
) -> PolynomialCoeffs<F> {
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<F: Field>(
result[i] = result_i;
result[j] = result_j;
}
result
PolynomialCoeffs { coeffs: result }
}
pub fn fft_with_precomputation_power_of_2<F: Field>(
coefficients: Vec<F>,
pub(crate) fn fft_with_precomputation_power_of_2<F: Field>(
poly: PolynomialCoeffs<F>,
precomputation: &FftPrecomputation<F>,
) -> Vec<F> {
) -> PolynomialValues<F> {
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<F: Field>(
}
// 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<F: Field>(coefficients: Vec<F>, shift: F) -> Vec<F> {
let mut points = fft(coefficients);
pub(crate) fn coset_fft<F: Field>(poly: PolynomialCoeffs<F>, shift: F) -> PolynomialValues<F> {
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<F: Field>(points: Vec<F>) -> Vec<F> {
let precomputation = fft_precompute(points.len());
ifft_with_precomputation_power_of_2(points, &precomputation)
pub(crate) fn ifft<F: Field>(poly: PolynomialValues<F>) -> PolynomialCoeffs<F> {
let precomputation = fft_precompute(poly.len());
ifft_with_precomputation_power_of_2(poly, &precomputation)
}
pub fn coset_ifft<F: Field>(points: Vec<F>, shift: F) -> Vec<F> {
pub(crate) fn coset_ifft<F: Field>(poly: PolynomialValues<F>, shift: F) -> PolynomialCoeffs<F> {
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<F: Field>(points: Vec<Vec<F>>, rate_bits: usize) -> Vec<Vec<F>> {
points.into_iter().map(|p| lde(p, rate_bits)).collect()
}
pub fn lde<F: Field>(points: Vec<F>, rate_bits: usize) -> Vec<F> {
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};

View File

@ -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<Output=Self>
+ Add<Self, Output=Self>
@ -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<Self> {
// 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<Self>;

View File

@ -1,4 +1,3 @@
pub(crate) mod batch_inverse;
pub(crate) mod crandall_field;
pub(crate) mod field;
pub(crate) mod field_search;

View File

@ -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;

View File

@ -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());
}

View File

@ -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<F: Field>(mut a: PolynomialCoeffs<F>, n: usize) -> PolynomialCoeffs<F> {
// 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::<Vec<_>>();
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
}
}

2
src/polynomial/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub(crate) mod division;
pub(crate) mod polynomial;

View File

@ -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<F: Field> {
pub(crate) values: Vec<F>,
}
impl<F: Field> PolynomialValues<F> {
pub(crate) fn new(values: Vec<F>) -> 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<Self>,
rate_bits: usize,
) -> Vec<Self> {
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<F: Field> {
pub(crate) coeffs: Vec<F>,
}
impl<F: Field> PolynomialCoeffs<F> {
pub(crate) fn new(coeffs: Vec<F>) -> 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<Self> {
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<Self>,
rate_bits: usize,
) -> Vec<Self> {
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 }
}
}

View File

@ -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<F: Field>(
prover_data: &ProverOnlyCircuitData<F>,
@ -27,6 +28,7 @@ pub(crate) fn prove<F: Field>(
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<F: Field>(
// 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<F: Field>(
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<F: Field>(
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<F> = 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<F: Field>(
}
}
fn compute_zs<F: Field>(common_data: &CommonCircuitData<F>) -> Vec<Vec<F>> {
fn compute_zs<F: Field>(common_data: &CommonCircuitData<F>) -> Vec<PolynomialValues<F>> {
(0..common_data.config.num_checks)
.map(|i| compute_z(common_data, i))
.collect()
}
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, i: usize) -> Vec<F> {
vec![F::ZERO; common_data.degree()] // TODO
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, i: usize) -> PolynomialValues<F> {
PolynomialValues::zero(common_data.degree()) // TODO
}
fn compute_vanishing_poly<F: Field>(
@ -97,7 +103,7 @@ fn compute_vanishing_poly<F: Field>(
wire_ldes_t: Vec<Vec<F>>,
plonk_z_lde_t: Vec<Vec<F>>,
alpha: F,
) -> Vec<F> {
) -> PolynomialValues<F> {
let lde_size = common_data.lde_size();
let lde_gen = common_data.lde_generator();
@ -129,7 +135,7 @@ fn compute_vanishing_poly<F: Field>(
point *= lde_gen;
}
debug_assert_eq!(point, F::ONE);
result
PolynomialValues::new(result)
}
fn compute_vanishing_poly_entry<F: Field>(
@ -150,7 +156,7 @@ fn compute_wire_lde<F: Field>(
witness: &PartialWitness<F>,
degree: usize,
rate_bits: usize,
) -> Vec<F> {
) -> PolynomialValues<F> {
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<F: Field>(
// 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)
}

View File

@ -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<F: Field>(polys: Vec<PolynomialValues<F>>) -> Vec<Vec<F>> {
let poly_values = polys.into_iter()
.map(|p| p.values)
.collect::<Vec<_>>();
transpose(&poly_values)
}
pub(crate) fn transpose<T: Clone>(matrix: &[Vec<T>]) -> Vec<Vec<T>> {
let old_rows = matrix.len();
let old_cols = matrix[0].len();