mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 14:23:07 +00:00
Refactor polynomial code
This commit is contained in:
parent
07718397ea
commit
6c8dfb97ac
@ -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 };
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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>;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
pub(crate) mod batch_inverse;
|
||||
pub(crate) mod crandall_field;
|
||||
pub(crate) mod field;
|
||||
pub(crate) mod field_search;
|
||||
|
||||
@ -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;
|
||||
|
||||
11
src/main.rs
11
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());
|
||||
}
|
||||
|
||||
66
src/polynomial/division.rs
Normal file
66
src/polynomial/division.rs
Normal 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
2
src/polynomial/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub(crate) mod division;
|
||||
pub(crate) mod polynomial;
|
||||
96
src/polynomial/polynomial.rs
Normal file
96
src/polynomial/polynomial.rs
Normal 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 }
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
10
src/util.rs
10
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<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();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user