First try

This commit is contained in:
wborgeaud 2021-11-19 18:11:14 +01:00
parent 2b4bb13ab0
commit aec88a8528
8 changed files with 167 additions and 27 deletions

View File

@ -160,12 +160,30 @@ impl<F: OEF<D>, const D: usize> PolynomialCoeffsAlgebra<F, D> {
.fold(ExtensionAlgebra::ZERO, |acc, &c| acc * x + c)
}
pub fn eval_with_powers(&self, powers: &[ExtensionAlgebra<F, D>]) -> ExtensionAlgebra<F, D> {
debug_assert_eq!(self.coeffs.len(), powers.len() + 1);
let acc = self.coeffs[0];
self.coeffs[1..]
.iter()
.zip(powers)
.fold(acc, |acc, (&x, &c)| acc + c * x)
}
pub fn eval_base(&self, x: F) -> ExtensionAlgebra<F, D> {
self.coeffs
.iter()
.rev()
.fold(ExtensionAlgebra::ZERO, |acc, &c| acc.scalar_mul(x) + c)
}
pub fn eval_base_with_powers(&self, powers: &[F]) -> ExtensionAlgebra<F, D> {
debug_assert_eq!(self.coeffs.len(), powers.len() + 1);
let acc = self.coeffs[0];
self.coeffs[1..]
.iter()
.zip(powers)
.fold(acc, |acc, (&x, &c)| acc + x.scalar_mul(c))
}
}
#[cfg(test)]

View File

@ -64,4 +64,24 @@ impl<const D: usize> PolynomialCoeffsExtAlgebraTarget<D> {
}
acc
}
pub fn eval_with_powers<F>(
&self,
builder: &mut CircuitBuilder<F, D>,
powers: &[ExtensionAlgebraTarget<D>],
) -> ExtensionAlgebraTarget<D>
where
F: RichField + Extendable<D>,
{
debug_assert_eq!(self.0.len(), powers.len() + 1);
let acc = self.0[0];
self.0[1..]
.iter()
.zip(powers)
.fold(acc, |acc, (&x, &c)| builder.mul_add_ext_algebra(c, x, acc))
// let mut acc = builder.zero_ext_algebra();
// for &c in self.0.iter().rev() {
// acc = builder.mul_add_ext_algebra(point, acc, c);
// }
// acc
}
}

View File

@ -51,7 +51,9 @@ pub(crate) fn test_low_degree<F: RichField + Extendable<D>, G: Gate<F, D>, const
);
let expected_eval_degree = WITNESS_DEGREE * gate.degree();
dbg!(WITNESS_DEGREE, gate.degree());
dbg!(&constraint_eval_degrees);
assert!(
constraint_eval_degrees
.iter()
@ -151,6 +153,7 @@ pub(crate) fn test_eval_fns<F: RichField + Extendable<D>, G: Gate<F, D>, const D
let evals_t = gate.eval_unfiltered_recursively(&mut builder, vars_t);
pw.set_extension_targets(&evals_t, &evals);
dbg!(builder.num_gates());
let data = builder.build();
let proof = data.prove(pw)?;
verify(proof, &data.verifier_only, &data.common)

View File

@ -1,10 +1,10 @@
use std::marker::PhantomData;
use std::ops::Range;
use crate::field::extension_field::algebra::PolynomialCoeffsAlgebra;
use crate::field::extension_field::algebra::{ExtensionAlgebra, PolynomialCoeffsAlgebra};
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::{Extendable, FieldExtension};
use crate::field::field_types::RichField;
use crate::field::field_types::{Field, RichField};
use crate::field::interpolation::interpolant;
use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget;
use crate::gates::gate::Gate;
@ -90,9 +90,26 @@ impl<F: RichField + Extendable<D>, const D: usize> InterpolationGate<F, D> {
start..start + D
}
pub fn powers_init(&self, i: usize) -> usize {
debug_assert!(0 < i && i < self.num_points());
if i == 1 {
return self.wire_shift();
}
self.start_coeffs() + self.num_points() * D + i
}
pub fn powers_eval(&self, i: usize) -> Range<usize> {
debug_assert!(0 < i && i < self.num_points());
if i == 1 {
return self.wires_evaluation_point();
}
let start = self.start_coeffs() + self.num_points() * D + self.num_points() - 1 + i * D;
start..start + D
}
/// End of wire indices, exclusive.
fn end(&self) -> usize {
self.start_coeffs() + self.num_points() * D
self.powers_eval(self.num_points() - 1).end
}
/// The domain of the points we're interpolating.
@ -138,19 +155,34 @@ impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for InterpolationG
let coeffs = (0..self.num_points())
.map(|i| vars.get_local_ext_algebra(self.wires_coeff(i)))
.collect();
let interpolant = PolynomialCoeffsAlgebra::new(coeffs);
.collect::<Vec<_>>();
let coset = self.coset_ext(vars.local_wires[self.wire_shift()]);
for (i, point) in coset.into_iter().enumerate() {
let mut powers_init = (1..self.num_points())
.map(|i| vars.local_wires[self.powers_init(i)])
.collect::<Vec<_>>();
powers_init.insert(0, F::Extension::ONE);
let ocoeffs = coeffs
.iter()
.zip(powers_init)
.map(|(&c, p)| c.scalar_mul(p))
.collect::<Vec<_>>();
let interpolant = PolynomialCoeffsAlgebra::new(coeffs);
let ointerpolant = PolynomialCoeffsAlgebra::new(ocoeffs);
for (i, point) in F::Extension::two_adic_subgroup(self.subgroup_bits)
.into_iter()
.enumerate()
{
let value = vars.get_local_ext_algebra(self.wires_value(i));
let computed_value = interpolant.eval_base(point);
let computed_value = ointerpolant.eval_base(point);
constraints.extend(&(value - computed_value).to_basefield_array());
}
let evaluation_point = vars.get_local_ext_algebra(self.wires_evaluation_point());
let mut evaluation_point_powers = (1..self.num_points())
.map(|i| vars.get_local_ext_algebra(self.powers_eval(i)))
.collect::<Vec<_>>();
let evaluation_value = vars.get_local_ext_algebra(self.wires_evaluation_value());
let computed_evaluation_value = interpolant.eval(evaluation_point);
let computed_evaluation_value = interpolant.eval_with_powers(&evaluation_point_powers);
constraints.extend(&(evaluation_value - computed_evaluation_value).to_basefield_array());
constraints
@ -161,19 +193,33 @@ impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for InterpolationG
let coeffs = (0..self.num_points())
.map(|i| vars.get_local_ext(self.wires_coeff(i)))
.collect();
.collect::<Vec<_>>();
let mut powers_init = (1..self.num_points())
.map(|i| vars.local_wires[self.powers_init(i)])
.collect::<Vec<_>>();
powers_init.insert(0, F::ONE);
let ocoeffs = coeffs
.iter()
.zip(powers_init)
.map(|(&c, p)| c.scalar_mul(p))
.collect::<Vec<_>>();
let interpolant = PolynomialCoeffs::new(coeffs);
let ointerpolant = PolynomialCoeffs::new(ocoeffs);
let coset = self.coset(vars.local_wires[self.wire_shift()]);
for (i, point) in coset.into_iter().enumerate() {
for (i, point) in F::two_adic_subgroup(self.subgroup_bits)
.into_iter()
.enumerate()
{
let value = vars.get_local_ext(self.wires_value(i));
let computed_value = interpolant.eval_base(point);
let computed_value = ointerpolant.eval_base(point);
constraints.extend(&(value - computed_value).to_basefield_array());
}
let evaluation_point = vars.get_local_ext(self.wires_evaluation_point());
let evaluation_point_powers = (1..self.num_points())
.map(|i| vars.get_local_ext(self.powers_eval(i)))
.collect::<Vec<_>>();
let evaluation_value = vars.get_local_ext(self.wires_evaluation_value());
let computed_evaluation_value = interpolant.eval(evaluation_point);
let computed_evaluation_value = interpolant.eval_with_powers(&evaluation_point_powers);
constraints.extend(&(evaluation_value - computed_evaluation_value).to_basefield_array());
constraints
@ -188,13 +234,26 @@ impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for InterpolationG
let coeffs = (0..self.num_points())
.map(|i| vars.get_local_ext_algebra(self.wires_coeff(i)))
.collect();
.collect::<Vec<_>>();
let mut powers_init = (1..self.num_points())
.map(|i| vars.local_wires[self.powers_init(i)])
.collect::<Vec<_>>();
powers_init.insert(0, builder.one_extension());
let ocoeffs = coeffs
.iter()
.zip(powers_init)
.map(|(&c, p)| builder.scalar_mul_ext_algebra(p, c))
.collect::<Vec<_>>();
let interpolant = PolynomialCoeffsExtAlgebraTarget(coeffs);
let ointerpolant = PolynomialCoeffsExtAlgebraTarget(ocoeffs);
let coset = self.coset_ext_recursive(builder, vars.local_wires[self.wire_shift()]);
for (i, point) in coset.into_iter().enumerate() {
for (i, point) in F::Extension::two_adic_subgroup(self.subgroup_bits)
.into_iter()
.enumerate()
{
let value = vars.get_local_ext_algebra(self.wires_value(i));
let computed_value = interpolant.eval_scalar(builder, point);
let point = builder.constant_extension(point);
let computed_value = ointerpolant.eval_scalar(builder, point);
constraints.extend(
&builder
.sub_ext_algebra(value, computed_value)
@ -202,9 +261,15 @@ impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for InterpolationG
);
}
let evaluation_point = vars.get_local_ext_algebra(self.wires_evaluation_point());
let evaluation_point_powers = (1..self.num_points())
.map(|i| vars.get_local_ext_algebra(self.powers_eval(i)))
.collect::<Vec<_>>();
let evaluation_value = vars.get_local_ext_algebra(self.wires_evaluation_value());
let computed_evaluation_value = interpolant.eval(builder, evaluation_point);
let computed_evaluation_value =
interpolant.eval_with_powers(builder, &evaluation_point_powers);
// let evaluation_point = vars.get_local_ext_algebra(self.wires_evaluation_point());
// let evaluation_value = vars.get_local_ext_algebra(self.wires_evaluation_value());
// let computed_evaluation_value = interpolant.eval(builder, evaluation_point);
constraints.extend(
&builder
.sub_ext_algebra(evaluation_value, computed_evaluation_value)
@ -238,7 +303,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for InterpolationG
fn degree(&self) -> usize {
// The highest power of x is `num_points - 1`, and then multiplication by the coefficient
// adds 1.
self.num_points()
2
}
fn num_constraints(&self) -> usize {
@ -357,7 +422,7 @@ mod tests {
#[test]
fn eval_fns() -> Result<()> {
test_eval_fns::<GoldilocksField, _, 4>(InterpolationGate::new(2))
test_eval_fns::<GoldilocksField, _, 4>(InterpolationGate::new(3))
}
#[test]

View File

@ -687,6 +687,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
marked_targets: self.marked_targets,
representative_map: forest.parents,
fft_root_table: Some(fft_root_table),
instances: self.gate_instances,
};
// The HashSet of gates will have a non-deterministic order. When converting to a Vec, we

View File

@ -9,7 +9,7 @@ use crate::field::field_types::{Field, RichField};
use crate::fri::commitment::PolynomialBatchCommitment;
use crate::fri::reduction_strategies::FriReductionStrategy;
use crate::fri::{FriConfig, FriParams};
use crate::gates::gate::PrefixedGate;
use crate::gates::gate::{GateInstance, PrefixedGate};
use crate::hash::hash_types::{HashOut, MerkleCapTarget};
use crate::hash::merkle_tree::MerkleCap;
use crate::iop::generator::WitnessGenerator;
@ -67,10 +67,10 @@ impl CircuitConfig {
rate_bits: 3,
num_challenges: 2,
zero_knowledge: false,
cap_height: 3,
cap_height: 4,
fri_config: FriConfig {
proof_of_work_bits: 15,
reduction_strategy: FriReductionStrategy::ConstantArityBits(3, 5),
reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5),
num_query_rounds: 26,
},
}
@ -177,6 +177,7 @@ pub(crate) struct ProverOnlyCircuitData<F: RichField + Extendable<D>, const D: u
pub representative_map: Vec<usize>,
/// Pre-computed roots for faster FFT.
pub fft_root_table: Option<FftRootTable<F>>,
pub instances: Vec<GateInstance<F, D>>,
}
/// Circuit data required by the verifier, but not the prover.

View File

@ -66,6 +66,17 @@ pub(crate) fn prove<F: RichField + Extendable<D>, const D: usize>(
.collect()
);
// let rows = (0..degree)
// .map(|i| wires_values.iter().map(|w| w.values[i]).collect::<Vec<_>>())
// .collect::<Vec<_>>();
// for (i, r) in rows.iter().enumerate() {
// let c = rows.iter().filter(|&x| x == r).count();
// let s = prover_data.instances[i].gate_ref.0.id();
// if c > 1 && !s.starts_with("Noop") {
// println!("{} {} {}", prover_data.instances[i].gate_ref.0.id(), i, c);
// }
// }
let wires_commitment = timed!(
timing,
"compute wires commitment",

View File

@ -120,6 +120,15 @@ impl<F: Field> PolynomialCoeffs<F> {
.fold(F::ZERO, |acc, &c| acc * x + c)
}
pub fn eval_with_powers(&self, powers: &[F]) -> F {
debug_assert_eq!(self.coeffs.len(), powers.len() + 1);
let acc = self.coeffs[0];
self.coeffs[1..]
.iter()
.zip(powers)
.fold(acc, |acc, (&x, &c)| acc + c * x)
}
pub fn eval_base<const D: usize>(&self, x: F::BaseField) -> F
where
F: FieldExtension<D>,
@ -130,6 +139,18 @@ impl<F: Field> PolynomialCoeffs<F> {
.fold(F::ZERO, |acc, &c| acc.scalar_mul(x) + c)
}
pub fn eval_base_with_powers<const D: usize>(&self, powers: &[F::BaseField]) -> F
where
F: FieldExtension<D>,
{
debug_assert_eq!(self.coeffs.len(), powers.len() + 1);
let acc = self.coeffs[0];
self.coeffs[1..]
.iter()
.zip(powers)
.fold(acc, |acc, (&x, &c)| acc + x.scalar_mul(c))
}
pub fn lde_multiple(polys: Vec<&Self>, rate_bits: usize) -> Vec<Self> {
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
}