diff --git a/src/field/extension_field/algebra.rs b/src/field/extension_field/algebra.rs index 21438262..37f70f52 100644 --- a/src/field/extension_field/algebra.rs +++ b/src/field/extension_field/algebra.rs @@ -160,12 +160,30 @@ impl, const D: usize> PolynomialCoeffsAlgebra { .fold(ExtensionAlgebra::ZERO, |acc, &c| acc * x + c) } + pub fn eval_with_powers(&self, powers: &[ExtensionAlgebra]) -> ExtensionAlgebra { + 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 { self.coeffs .iter() .rev() .fold(ExtensionAlgebra::ZERO, |acc, &c| acc.scalar_mul(x) + c) } + + pub fn eval_base_with_powers(&self, powers: &[F]) -> ExtensionAlgebra { + 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)] diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs index 9f631c10..48a5f8b7 100644 --- a/src/gadgets/polynomial.rs +++ b/src/gadgets/polynomial.rs @@ -64,4 +64,24 @@ impl PolynomialCoeffsExtAlgebraTarget { } acc } + pub fn eval_with_powers( + &self, + builder: &mut CircuitBuilder, + powers: &[ExtensionAlgebraTarget], + ) -> ExtensionAlgebraTarget + where + F: RichField + Extendable, + { + 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 + } } diff --git a/src/gates/gate_testing.rs b/src/gates/gate_testing.rs index 9fe8e835..15c17ba7 100644 --- a/src/gates/gate_testing.rs +++ b/src/gates/gate_testing.rs @@ -51,7 +51,9 @@ pub(crate) fn test_low_degree, G: Gate, 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, G: Gate, 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) diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index d97eb009..536c87bb 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -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, const D: usize> InterpolationGate { 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 { + 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, const D: usize> Gate 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::>(); - 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::>(); + powers_init.insert(0, F::Extension::ONE); + let ocoeffs = coeffs + .iter() + .zip(powers_init) + .map(|(&c, p)| c.scalar_mul(p)) + .collect::>(); + 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::>(); 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, const D: usize> Gate for InterpolationG let coeffs = (0..self.num_points()) .map(|i| vars.get_local_ext(self.wires_coeff(i))) - .collect(); + .collect::>(); + let mut powers_init = (1..self.num_points()) + .map(|i| vars.local_wires[self.powers_init(i)]) + .collect::>(); + powers_init.insert(0, F::ONE); + let ocoeffs = coeffs + .iter() + .zip(powers_init) + .map(|(&c, p)| c.scalar_mul(p)) + .collect::>(); 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::>(); 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, const D: usize> Gate for InterpolationG let coeffs = (0..self.num_points()) .map(|i| vars.get_local_ext_algebra(self.wires_coeff(i))) - .collect(); + .collect::>(); + let mut powers_init = (1..self.num_points()) + .map(|i| vars.local_wires[self.powers_init(i)]) + .collect::>(); + 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::>(); 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, const D: usize> Gate 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::>(); 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, const D: usize> Gate 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::(InterpolationGate::new(2)) + test_eval_fns::(InterpolationGate::new(3)) } #[test] diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index 32ea59b6..f19d6ae9 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -687,6 +687,7 @@ impl, const D: usize> CircuitBuilder { 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 diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index c2a8d6d0..c0ccbc3c 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -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, const D: u pub representative_map: Vec, /// Pre-computed roots for faster FFT. pub fft_root_table: Option>, + pub instances: Vec>, } /// Circuit data required by the verifier, but not the prover. diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 3f8e607d..b5175f02 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -66,6 +66,17 @@ pub(crate) fn prove, const D: usize>( .collect() ); + // let rows = (0..degree) + // .map(|i| wires_values.iter().map(|w| w.values[i]).collect::>()) + // .collect::>(); + // 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", diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index a021ecd2..3c732208 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -120,6 +120,15 @@ impl PolynomialCoeffs { .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(&self, x: F::BaseField) -> F where F: FieldExtension, @@ -130,6 +139,18 @@ impl PolynomialCoeffs { .fold(F::ZERO, |acc, &c| acc.scalar_mul(x) + c) } + pub fn eval_base_with_powers(&self, powers: &[F::BaseField]) -> F + where + F: FieldExtension, + { + 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 { polys.into_iter().map(|p| p.lde(rate_bits)).collect() }