mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 23:03:08 +00:00
Finish up
This commit is contained in:
parent
3311981fc4
commit
6e83d956e9
67
src/gates/gate_testing.rs
Normal file
67
src/gates/gate_testing.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use crate::field::field::Field;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
use crate::util::{log2_ceil, transpose};
|
||||
use crate::vars::EvaluationVars;
|
||||
|
||||
const WITNESS_SIZE: usize = 1 << 5;
|
||||
const WITNESS_DEGREE: usize = WITNESS_SIZE - 1;
|
||||
|
||||
/// Tests that the constraints imposed by the given gate are low-degree by applying them to random
|
||||
/// low-degree witness polynomials.
|
||||
pub(crate) fn test_low_degree<F: Field, G: Gate<F>>(gate: G) {
|
||||
let rate_bits = log2_ceil(gate.degree() + 1);
|
||||
|
||||
let wire_ldes = random_low_degree_matrix(gate.num_wires(), rate_bits);
|
||||
let constant_ldes = random_low_degree_matrix::<F>(gate.num_constants(), rate_bits);
|
||||
assert_eq!(wire_ldes.len(), constant_ldes.len());
|
||||
|
||||
let constraint_evals = wire_ldes
|
||||
.iter()
|
||||
.zip(constant_ldes.iter())
|
||||
.map(|(local_wires, local_constants)| EvaluationVars {
|
||||
local_constants,
|
||||
local_wires,
|
||||
})
|
||||
.map(|vars| gate.eval_unfiltered(vars))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let constraint_eval_degrees = transpose(&constraint_evals)
|
||||
.into_iter()
|
||||
.map(PolynomialValues::new)
|
||||
.map(|p| p.degree())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let expected_eval_degree = WITNESS_DEGREE * gate.degree();
|
||||
|
||||
assert!(
|
||||
constraint_eval_degrees
|
||||
.iter()
|
||||
.all(|°| deg <= expected_eval_degree),
|
||||
"Expected degrees at most {} * {} = {}, actual {:?}",
|
||||
WITNESS_SIZE,
|
||||
gate.degree(),
|
||||
expected_eval_degree,
|
||||
constraint_eval_degrees
|
||||
);
|
||||
}
|
||||
|
||||
fn random_low_degree_matrix<F: Field>(num_polys: usize, rate_bits: usize) -> Vec<Vec<F>> {
|
||||
let polys = (0..num_polys)
|
||||
.map(|_| random_low_degree_values(rate_bits))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if polys.is_empty() {
|
||||
// We want a Vec of many empty Vecs, whereas transpose would just give an empty Vec.
|
||||
vec![Vec::new(); WITNESS_SIZE << rate_bits]
|
||||
} else {
|
||||
transpose(&polys)
|
||||
}
|
||||
}
|
||||
|
||||
fn random_low_degree_values<F: Field>(rate_bits: usize) -> Vec<F> {
|
||||
PolynomialCoeffs::new(F::rand_vec(WITNESS_SIZE))
|
||||
.lde(rate_bits)
|
||||
.fft()
|
||||
.values
|
||||
}
|
||||
@ -106,10 +106,18 @@ impl<F: Field + Extendable<D>, const D: usize> Gate<F> for QuarticInterpolationG
|
||||
.map(|i| vars.get_local_ext(self.wires_coeff(i)))
|
||||
.collect();
|
||||
let interpolant = PolynomialCoeffs::new(coeffs);
|
||||
let x_eval = vars.get_local_ext(self.wires_evaluation_point());
|
||||
let x_eval_powers = x_eval.powers().take(self.num_points);
|
||||
|
||||
// TODO
|
||||
for i in 0..self.num_points {
|
||||
let point = F::Extension::from_basefield(vars.local_wires[self.wire_point(i)]);
|
||||
let value = vars.get_local_ext(self.wires_value(i));
|
||||
let computed_value = interpolant.eval(point);
|
||||
constraints.extend(&(value - computed_value).to_basefield_array());
|
||||
}
|
||||
|
||||
let evaluation_point = vars.get_local_ext(self.wires_evaluation_point());
|
||||
let evaluation_value = vars.get_local_ext(self.wires_evaluation_value());
|
||||
let computed_evaluation_value = interpolant.eval(evaluation_point);
|
||||
constraints.extend(&(evaluation_value - computed_evaluation_value).to_basefield_array());
|
||||
|
||||
constraints
|
||||
}
|
||||
@ -144,11 +152,15 @@ impl<F: Field + Extendable<D>, const D: usize> Gate<F> for QuarticInterpolationG
|
||||
}
|
||||
|
||||
fn degree(&self) -> usize {
|
||||
self.num_points - 1
|
||||
// The highest power of x is `num_points - 1`, and then multiplication by the coefficient
|
||||
// adds 1.
|
||||
self.num_points
|
||||
}
|
||||
|
||||
fn num_constraints(&self) -> usize {
|
||||
todo!()
|
||||
// num_points * D constraints to check for consistency between the coefficients and the
|
||||
// point-value pairs, plus D constraints for the evaluation value.
|
||||
self.num_points * D + D
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,14 +243,16 @@ mod tests {
|
||||
|
||||
use crate::field::crandall_field::CrandallField;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::gates::gate_testing::test_low_degree;
|
||||
use crate::gates::interpolation_quartic::QuarticInterpolationGate;
|
||||
|
||||
#[test]
|
||||
fn wire_indices_2_points() {
|
||||
fn wire_indices() {
|
||||
let gate = QuarticInterpolationGate::<CrandallField, 4> {
|
||||
num_points: 2,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
// The exact indices aren't really important, but we want to make sure we don't have any
|
||||
// overlaps or gaps.
|
||||
assert_eq!(gate.wire_point(0), 0);
|
||||
@ -253,11 +267,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wire_indices_4_points() {
|
||||
let gate = QuarticInterpolationGate::<CrandallField, 4> {
|
||||
fn low_degree() {
|
||||
type F = CrandallField;
|
||||
let gate = QuarticInterpolationGate::<F, 4> {
|
||||
num_points: 4,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
assert_eq!(gate.num_wires(), 44);
|
||||
test_low_degree(gate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,3 +6,6 @@ pub mod gmimc;
|
||||
pub(crate) mod gmimc_eval;
|
||||
mod interpolation_quartic;
|
||||
pub(crate) mod noop;
|
||||
|
||||
#[cfg(test)]
|
||||
mod gate_testing;
|
||||
|
||||
@ -32,6 +32,7 @@ impl<F: Field> PolynomialValues<F> {
|
||||
pub fn ifft(self) -> PolynomialCoeffs<F> {
|
||||
ifft(self)
|
||||
}
|
||||
|
||||
pub fn lde_multiple(polys: Vec<Self>, rate_bits: usize) -> Vec<Self> {
|
||||
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
|
||||
}
|
||||
@ -40,6 +41,16 @@ impl<F: Field> PolynomialValues<F> {
|
||||
let coeffs = ifft(self).lde(rate_bits);
|
||||
fft(coeffs)
|
||||
}
|
||||
|
||||
pub fn degree(&self) -> usize {
|
||||
self.degree_plus_one()
|
||||
.checked_sub(1)
|
||||
.expect("deg(0) is undefined")
|
||||
}
|
||||
|
||||
pub fn degree_plus_one(&self) -> usize {
|
||||
self.clone().ifft().degree_plus_one()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> From<Vec<F>> for PolynomialValues<F> {
|
||||
|
||||
@ -32,6 +32,10 @@ pub(crate) fn transpose_poly_values<F: Field>(polys: Vec<PolynomialValues<F>>) -
|
||||
}
|
||||
|
||||
pub(crate) fn transpose<T: Clone>(matrix: &[Vec<T>]) -> Vec<Vec<T>> {
|
||||
if matrix.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let old_rows = matrix.len();
|
||||
let old_cols = matrix[0].len();
|
||||
let mut transposed = vec![Vec::with_capacity(old_rows); old_cols];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user