diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index c9f15aec..4cfd837a 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -41,23 +41,14 @@ impl, const D: usize> CircuitBuilder { let coset_start = self.mul(start, x); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. - let g_powers = g + let points = g .powers() - .take(arity) - .map(|y| self.constant(y)) + .map(|y| { + let yc = self.constant(y); + self.mul(coset_start, yc) + }) + .zip(evals) .collect::>(); - let mut coset = Vec::new(); - for i in 0..arity / 2 { - let res = self.mul_two( - coset_start, - g_powers[2 * i], - coset_start, - g_powers[2 * i + 1], - ); - coset.push(res.0); - coset.push(res.1); - } - let points = coset.into_iter().zip(evals).collect::>(); self.interpolate(&points, beta) } @@ -100,7 +91,7 @@ impl, const D: usize> CircuitBuilder { // Size of the LDE domain. let n = proof.final_poly.len() << (total_arities + config.rate_bits); - challenger.observe_opening_set(&os); + challenger.observe_opening_set(os); // Scaling factor to combine polynomials. let alpha = challenger.get_extension_challenge(self); @@ -265,14 +256,11 @@ impl, const D: usize> CircuitBuilder { precomputed_reduced_evals.slope, precomputed_reduced_evals.zs, ); - let (zs_numerator, vanish_zeta_right) = self.sub_two_extension( - zs_composition_eval, - interpol_val, - subgroup_x, - precomputed_reduced_evals.zeta_right, - ); - let (mut sum, zs_denominator) = - alpha.shift_and_mul(sum, vanish_zeta, vanish_zeta_right, self); + let zs_numerator = self.sub_extension(zs_composition_eval, interpol_val); + let vanish_zeta_right = + self.sub_extension(subgroup_x, precomputed_reduced_evals.zeta_right); + sum = alpha.shift(sum, self); + let zs_denominator = self.mul_extension(vanish_zeta, vanish_zeta_right); sum = self.div_add_extension(zs_numerator, zs_denominator, sum); sum @@ -296,8 +284,8 @@ impl, const D: usize> CircuitBuilder { // TODO: Do we need to range check `x_index` to a target smaller than `p`? let x_index = challenger.get_challenge(self); let mut x_index_bits = self.low_bits(x_index, n_log, 64); - let cap_index = self - .le_sum(x_index_bits[x_index_bits.len() - common_data.config.cap_height..].into_iter()); + let cap_index = + self.le_sum(x_index_bits[x_index_bits.len() - common_data.config.cap_height..].iter()); with_context!( self, "check FRI initial proof", @@ -317,19 +305,10 @@ impl, const D: usize> CircuitBuilder { let phi = self.exp_from_bits(phi, x_index_bits.iter().rev()); let g_ext = self.convert_to_ext(g); let phi_ext = self.convert_to_ext(phi); - let zero = self.zero_extension(); // `subgroup_x = g*phi, vanish_zeta = g*phi - zeta` - let tmp = self.double_arithmetic_extension( - F::ONE, - F::NEG_ONE, - g_ext, - phi_ext, - zero, - g_ext, - phi_ext, - zeta, - ); - (tmp.0 .0[0], tmp.1) + let subgroup_x = self.mul(g, phi); + let vanish_zeta = self.mul_sub_extension(g_ext, phi_ext, zeta); + (subgroup_x, vanish_zeta) }); // old_eval is the last derived evaluation; it will be checked for consistency with its @@ -369,7 +348,7 @@ impl, const D: usize> CircuitBuilder { "infer evaluation using interpolation", self.compute_evaluation( subgroup_x, - &x_index_within_coset_bits, + x_index_within_coset_bits, arity_bits, evals, betas[i], @@ -409,7 +388,6 @@ impl, const D: usize> CircuitBuilder { struct PrecomputedReducedEvalsTarget { pub single: ExtensionTarget, pub zs: ExtensionTarget, - pub zs_right: ExtensionTarget, /// Slope of the line from `(zeta, zs)` to `(zeta_right, zs_right)`. pub slope: ExtensionTarget, pub zeta_right: ExtensionTarget, @@ -440,12 +418,12 @@ impl PrecomputedReducedEvalsTarget { let g = builder.constant_extension(F::Extension::primitive_root_of_unity(degree_log)); let zeta_right = builder.mul_extension(g, zeta); - let (numerator, denominator) = builder.sub_two_extension(zs_right, zs, zeta_right, zeta); + let numerator = builder.sub_extension(zs_right, zs); + let denominator = builder.sub_extension(zeta_right, zeta); Self { single, zs, - zs_right, slope: builder.div_extension(numerator, denominator), zeta_right, } diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 2c41482e..52b1d660 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -86,16 +86,6 @@ impl, const D: usize> CircuitBuilder { self.arithmetic(F::ONE, x, y, F::ZERO, x) } - /// Computes `x * y`. - pub fn mul_two(&mut self, a0: Target, b0: Target, a1: Target, b1: Target) -> (Target, Target) { - let a0_ext = self.convert_to_ext(a0); - let b0_ext = self.convert_to_ext(b0); - let a1_ext = self.convert_to_ext(a1); - let b1_ext = self.convert_to_ext(b1); - let res = self.mul_two_extension(a0_ext, b0_ext, a1_ext, b1_ext); - (res.0 .0[0], res.1 .0[0]) - } - /// Multiply `n` `Target`s with `ceil(n/2) + 1` `ArithmeticExtensionGate`s. pub fn mul_many(&mut self, terms: &[Target]) -> Target { let terms_ext = terms diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 7ab8d359..b11447df 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -1,12 +1,11 @@ use std::convert::TryInto; -use itertools::Itertools; use num::Integer; use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget}; use crate::field::extension_field::{Extendable, OEF}; use crate::field::field_types::Field; -use crate::gates::arithmetic::ArithmeticExtensionGate; +use crate::gates::arithmetic::{ArithmeticExtensionGate, NUM_ARITHMETIC_OPS}; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; use crate::iop::target::Target; use crate::iop::witness::PartialWitness; @@ -14,51 +13,28 @@ use crate::plonk::circuit_builder::CircuitBuilder; use crate::util::bits_u64; impl, const D: usize> CircuitBuilder { - pub fn double_arithmetic_extension( - &mut self, - const_0: F, - const_1: F, - first_multiplicand_0: ExtensionTarget, - first_multiplicand_1: ExtensionTarget, - first_addend: ExtensionTarget, - second_multiplicand_0: ExtensionTarget, - second_multiplicand_1: ExtensionTarget, - second_addend: ExtensionTarget, - ) -> (ExtensionTarget, ExtensionTarget) { - let gate = self.add_gate(ArithmeticExtensionGate, vec![const_0, const_1]); + /// Finds the last available arithmetic gate with the given constants or add one if there aren't any. + /// Returns `(g,i)` such that there is an arithmetic gate with the given constants at index + /// `g` and the gate's `i`-th operation is available. + fn find_arithmetic_gate(&mut self, const_0: F, const_1: F) -> (usize, usize) { + let (gate, i) = self + .free_arithmetic + .get(&(const_0, const_1)) + .copied() + .unwrap_or_else(|| { + let gate = self.add_gate(ArithmeticExtensionGate, vec![const_0, const_1]); + (gate, 0) + }); - let wire_first_multiplicand_0 = ExtensionTarget::from_range( - gate, - ArithmeticExtensionGate::::wires_first_multiplicand_0(), - ); - let wire_first_multiplicand_1 = ExtensionTarget::from_range( - gate, - ArithmeticExtensionGate::::wires_first_multiplicand_1(), - ); - let wire_first_addend = - ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_first_addend()); - let wire_second_multiplicand_0 = ExtensionTarget::from_range( - gate, - ArithmeticExtensionGate::::wires_second_multiplicand_0(), - ); - let wire_second_multiplicand_1 = ExtensionTarget::from_range( - gate, - ArithmeticExtensionGate::::wires_second_multiplicand_1(), - ); - let wire_second_addend = - ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_second_addend()); - let wire_first_output = - ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_first_output()); - let wire_second_output = - ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_second_output()); + // Update `free_arithmetic` with new values. + if i < NUM_ARITHMETIC_OPS - 1 { + self.free_arithmetic + .insert((const_0, const_1), (gate, i + 1)); + } else { + self.free_arithmetic.remove(&(const_0, const_1)); + } - self.route_extension(first_multiplicand_0, wire_first_multiplicand_0); - self.route_extension(first_multiplicand_1, wire_first_multiplicand_1); - self.route_extension(first_addend, wire_first_addend); - self.route_extension(second_multiplicand_0, wire_second_multiplicand_0); - self.route_extension(second_multiplicand_1, wire_second_multiplicand_1); - self.route_extension(second_addend, wire_second_addend); - (wire_first_output, wire_second_output) + (gate, i) } pub fn arithmetic_extension( @@ -80,18 +56,23 @@ impl, const D: usize> CircuitBuilder { return result; } - let zero = self.zero_extension(); - self.double_arithmetic_extension( - const_0, - const_1, - multiplicand_0, - multiplicand_1, - addend, - zero, - zero, - zero, - ) - .0 + let (gate, i) = self.find_arithmetic_gate(const_0, const_1); + let wires_multiplicand_0 = ExtensionTarget::from_range( + gate, + ArithmeticExtensionGate::::wires_ith_multiplicand_0(i), + ); + let wires_multiplicand_1 = ExtensionTarget::from_range( + gate, + ArithmeticExtensionGate::::wires_ith_multiplicand_1(i), + ); + let wires_addend = + ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_ith_addend(i)); + + self.route_extension(multiplicand_0, wires_multiplicand_0); + self.route_extension(multiplicand_1, wires_multiplicand_1); + self.route_extension(addend, wires_addend); + + ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_ith_output(i)) } /// Checks for special cases where the value of @@ -172,21 +153,8 @@ impl, const D: usize> CircuitBuilder { pairs: Vec<(ExtensionTarget, ExtensionTarget)>, ) -> ExtensionTarget { let mut acc = starting_acc; - for chunk in pairs.chunks_exact(2) { - let (a0, b0) = chunk[0]; - let (a1, b1) = chunk[1]; - let gate = self.num_gates(); - let first_out = ExtensionTarget::from_range( - gate, - ArithmeticExtensionGate::::wires_first_output(), - ); - acc = self - .double_arithmetic_extension(constant, F::ONE, a0, b0, acc, a1, b1, first_out) - .1; - } - if pairs.len().is_odd() { - let n = pairs.len() - 1; - acc = self.arithmetic_extension(constant, F::ONE, pairs[n].0, pairs[n].1, acc); + for (a, b) in pairs { + acc = self.arithmetic_extension(constant, F::ONE, a, b, acc); } acc } @@ -200,38 +168,15 @@ impl, const D: usize> CircuitBuilder { self.arithmetic_extension(F::ONE, F::ONE, one, a, b) } - /// Returns `(a0+b0, a1+b1)`. - pub fn add_two_extension( - &mut self, - a0: ExtensionTarget, - b0: ExtensionTarget, - a1: ExtensionTarget, - b1: ExtensionTarget, - ) -> (ExtensionTarget, ExtensionTarget) { - let one = self.one_extension(); - self.double_arithmetic_extension(F::ONE, F::ONE, one, a0, b0, one, a1, b1) - } - pub fn add_ext_algebra( &mut self, - a: ExtensionAlgebraTarget, + mut a: ExtensionAlgebraTarget, b: ExtensionAlgebraTarget, ) -> ExtensionAlgebraTarget { - // We run two additions in parallel. So `[a0,a1,a2,a3] + [b0,b1,b2,b3]` is computed with two - // `add_two_extension`, first `[a0,a1]+[b0,b1]` then `[a2,a3]+[b2,b3]`. - let mut res = Vec::with_capacity(D); - // We need some extra logic if D is odd. - let d_even = D & (D ^ 1); // = 2 * (D/2) - for mut chunk in &(0..d_even).chunks(2) { - let i = chunk.next().unwrap(); - let j = chunk.next().unwrap(); - let (o0, o1) = self.add_two_extension(a.0[i], b.0[i], a.0[j], b.0[j]); - res.extend([o0, o1]); + for i in 0..D { + a.0[i] = self.add_extension(a.0[i], b.0[i]); } - if D.is_odd() { - res.push(self.add_extension(a.0[D - 1], b.0[D - 1])); - } - ExtensionAlgebraTarget(res.try_into().unwrap()) + a } /// Add 3 `ExtensionTarget`s with 1 `ArithmeticExtensionGate`s. @@ -274,35 +219,15 @@ impl, const D: usize> CircuitBuilder { self.arithmetic_extension(F::ONE, F::NEG_ONE, one, a, b) } - pub fn sub_two_extension( - &mut self, - a0: ExtensionTarget, - b0: ExtensionTarget, - a1: ExtensionTarget, - b1: ExtensionTarget, - ) -> (ExtensionTarget, ExtensionTarget) { - let one = self.one_extension(); - self.double_arithmetic_extension(F::ONE, F::NEG_ONE, one, a0, b0, one, a1, b1) - } - pub fn sub_ext_algebra( &mut self, - a: ExtensionAlgebraTarget, + mut a: ExtensionAlgebraTarget, b: ExtensionAlgebraTarget, ) -> ExtensionAlgebraTarget { - // See `add_ext_algebra`. - let mut res = Vec::with_capacity(D); - let d_even = D & (D ^ 1); // = 2 * (D/2) - for mut chunk in &(0..d_even).chunks(2) { - let i = chunk.next().unwrap(); - let j = chunk.next().unwrap(); - let (o0, o1) = self.sub_two_extension(a.0[i], b.0[i], a.0[j], b.0[j]); - res.extend([o0, o1]); + for i in 0..D { + a.0[i] = self.sub_extension(a.0[i], b.0[i]); } - if D.is_odd() { - res.push(self.sub_extension(a.0[D - 1], b.0[D - 1])); - } - ExtensionAlgebraTarget(res.try_into().unwrap()) + a } pub fn mul_extension_with_const( @@ -312,17 +237,7 @@ impl, const D: usize> CircuitBuilder { multiplicand_1: ExtensionTarget, ) -> ExtensionTarget { let zero = self.zero_extension(); - self.double_arithmetic_extension( - const_0, - F::ZERO, - multiplicand_0, - multiplicand_1, - zero, - zero, - zero, - zero, - ) - .0 + self.arithmetic_extension(const_0, F::ZERO, multiplicand_0, multiplicand_1, zero) } pub fn mul_extension( @@ -333,18 +248,6 @@ impl, const D: usize> CircuitBuilder { self.mul_extension_with_const(F::ONE, multiplicand_0, multiplicand_1) } - /// Returns `(a0*b0, a1*b1)`. - pub fn mul_two_extension( - &mut self, - a0: ExtensionTarget, - b0: ExtensionTarget, - a1: ExtensionTarget, - b1: ExtensionTarget, - ) -> (ExtensionTarget, ExtensionTarget) { - let zero = self.zero_extension(); - self.double_arithmetic_extension(F::ONE, F::ZERO, a0, b0, zero, a1, b1, zero) - } - /// Computes `x^2`. pub fn square_extension(&mut self, x: ExtensionTarget) -> ExtensionTarget { self.mul_extension(x, x) @@ -402,12 +305,8 @@ impl, const D: usize> CircuitBuilder { b: ExtensionTarget, c: ExtensionTarget, ) -> ExtensionTarget { - let zero = self.zero_extension(); - let gate = self.num_gates(); - let first_out = - ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_first_output()); - self.double_arithmetic_extension(F::ONE, F::ZERO, a, b, zero, c, first_out, zero) - .1 + let tmp = self.mul_extension(a, b); + self.mul_extension(tmp, c) } /// Multiply `n` `ExtensionTarget`s with `n/2` `ArithmeticExtensionGate`s. @@ -484,22 +383,8 @@ impl, const D: usize> CircuitBuilder { b: ExtensionAlgebraTarget, mut c: ExtensionAlgebraTarget, ) -> ExtensionAlgebraTarget { - for i in 0..D / 2 { - let res = self.double_arithmetic_extension( - F::ONE, - F::ONE, - a, - b.0[2 * i], - c.0[2 * i], - a, - b.0[2 * i + 1], - c.0[2 * i + 1], - ); - c.0[2 * i] = res.0; - c.0[2 * i + 1] = res.1; - } - if D.is_odd() { - c.0[D - 1] = self.arithmetic_extension(F::ONE, F::ONE, a, b.0[D - 1], c.0[D - 1]); + for i in 0..D { + c.0[i] = self.mul_add_extension(a, b.0[i], c.0[i]); } c } @@ -571,7 +456,6 @@ impl, const D: usize> CircuitBuilder { z: ExtensionTarget, ) -> ExtensionTarget { let inv = self.add_virtual_extension_target(); - let zero = self.zero_extension(); let one = self.one_extension(); self.add_generator(QuotientGeneratorExtension { numerator: one, @@ -580,11 +464,10 @@ impl, const D: usize> CircuitBuilder { }); // Enforce that x times its purported inverse equals 1. - let (y_inv, res) = - self.double_arithmetic_extension(F::ONE, F::ONE, y, inv, zero, x, inv, z); + let y_inv = self.mul_extension(y, inv); self.assert_equal_extension(y_inv, one); - res + self.mul_add_extension(x, inv, z) } /// Computes `1 / x`. Results in an unsatisfiable instance if `x = 0`. diff --git a/src/gadgets/interpolation.rs b/src/gadgets/interpolation.rs index 9d48a204..6db70b6e 100644 --- a/src/gadgets/interpolation.rs +++ b/src/gadgets/interpolation.rs @@ -5,29 +5,6 @@ use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; impl, const D: usize> CircuitBuilder { - /// Interpolate two points. No need for an `InterpolationGate` since the coefficients - /// of the linear interpolation polynomial can be easily computed with arithmetic operations. - pub fn interpolate2( - &mut self, - interpolation_points: [(ExtensionTarget, ExtensionTarget); 2], - evaluation_point: ExtensionTarget, - ) -> ExtensionTarget { - // a0 -> a1 - // b0 -> b1 - // x -> a1 + (x-a0)*(b1-a1)/(b0-a0) - - let (x_m_a0, b1_m_a1) = self.sub_two_extension( - evaluation_point, - interpolation_points[0].0, - interpolation_points[1].1, - interpolation_points[0].1, - ); - let b0_m_a0 = self.sub_extension(interpolation_points[1].0, interpolation_points[0].0); - let quotient = self.div_extension(b1_m_a1, b0_m_a0); - - self.mul_add_extension(x_m_a0, quotient, interpolation_points[0].1) - } - /// Interpolate a list of point/evaluation pairs at a given point. /// Returns the evaluation of the interpolated polynomial at `evaluation_point`. pub fn interpolate( @@ -108,39 +85,4 @@ mod tests { verify(proof, &data.verifier_only, &data.common) } - - #[test] - fn test_interpolate2() -> Result<()> { - type F = CrandallField; - type FF = QuarticCrandallField; - let config = CircuitConfig::large_zk_config(); - let pw = PartialWitness::new(config.num_wires); - let mut builder = CircuitBuilder::::new(config); - - let len = 2; - let points = (0..len) - .map(|_| (FF::rand(), FF::rand())) - .collect::>(); - - let true_interpolant = interpolant(&points); - - let z = FF::rand(); - let true_eval = true_interpolant.eval(z); - - let points_target = points - .iter() - .map(|&(p, v)| (builder.constant_extension(p), builder.constant_extension(v))) - .collect::>(); - - let zt = builder.constant_extension(z); - - let eval = builder.interpolate2(points_target.try_into().unwrap(), zt); - let true_eval_target = builder.constant_extension(true_eval); - builder.assert_equal_extension(eval, true_eval_target); - - let data = builder.build(); - let proof = data.prove(pw)?; - - verify(proof, &data.verifier_only, &data.common) - } } diff --git a/src/gadgets/select.rs b/src/gadgets/select.rs index c81dd37b..3be3455c 100644 --- a/src/gadgets/select.rs +++ b/src/gadgets/select.rs @@ -1,6 +1,5 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::gates::arithmetic::ArithmeticExtensionGate; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; @@ -25,12 +24,8 @@ impl, const D: usize> CircuitBuilder { x: ExtensionTarget, y: ExtensionTarget, ) -> ExtensionTarget { - let gate = self.num_gates(); - // Holds `by - y`. - let first_out = - ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_first_output()); - self.double_arithmetic_extension(F::ONE, F::NEG_ONE, b, y, y, b, x, first_out) - .1 + let tmp = self.mul_sub_extension(b, y, y); + self.mul_sub_extension(b, x, tmp) } /// See `select_ext`. diff --git a/src/gates/arithmetic.rs b/src/gates/arithmetic.rs index 499bd4a7..c8f8f59c 100644 --- a/src/gates/arithmetic.rs +++ b/src/gates/arithmetic.rs @@ -10,34 +10,25 @@ use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; +/// Number of arithmetic operations performed by an arithmetic gate. +pub const NUM_ARITHMETIC_OPS: usize = 4; + /// A gate which can a linear combination `c0*x*y+c1*z` twice with the same `x`. #[derive(Debug)] pub struct ArithmeticExtensionGate; impl ArithmeticExtensionGate { - pub fn wires_first_multiplicand_0() -> Range { - 0..D + pub fn wires_ith_multiplicand_0(i: usize) -> Range { + 4 * D * i..4 * D * i + D } - pub fn wires_first_multiplicand_1() -> Range { - D..2 * D + pub fn wires_ith_multiplicand_1(i: usize) -> Range { + 4 * D * i + D..4 * D * i + 2 * D } - pub fn wires_first_addend() -> Range { - 2 * D..3 * D + pub fn wires_ith_addend(i: usize) -> Range { + 4 * D * i + 2 * D..4 * D * i + 3 * D } - pub fn wires_second_multiplicand_0() -> Range { - 3 * D..4 * D - } - pub fn wires_second_multiplicand_1() -> Range { - 4 * D..5 * D - } - pub fn wires_second_addend() -> Range { - 5 * D..6 * D - } - pub fn wires_first_output() -> Range { - 6 * D..7 * D - } - pub fn wires_second_output() -> Range { - 7 * D..8 * D + pub fn wires_ith_output(i: usize) -> Range { + 4 * D * i + 3 * D..4 * D * i + 4 * D } } @@ -50,24 +41,18 @@ impl, const D: usize> Gate for ArithmeticExtensionGate let const_0 = vars.local_constants[0]; let const_1 = vars.local_constants[1]; - let first_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_0()); - let first_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_1()); - let first_addend = vars.get_local_ext_algebra(Self::wires_first_addend()); - let second_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_0()); - let second_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_1()); - let second_addend = vars.get_local_ext_algebra(Self::wires_second_addend()); - let first_output = vars.get_local_ext_algebra(Self::wires_first_output()); - let second_output = vars.get_local_ext_algebra(Self::wires_second_output()); + let mut constraints = Vec::new(); + for i in 0..NUM_ARITHMETIC_OPS { + let multiplicand_0 = vars.get_local_ext_algebra(Self::wires_ith_multiplicand_0(i)); + let multiplicand_1 = vars.get_local_ext_algebra(Self::wires_ith_multiplicand_1(i)); + let addend = vars.get_local_ext_algebra(Self::wires_ith_addend(i)); + let output = vars.get_local_ext_algebra(Self::wires_ith_output(i)); + let computed_output = + multiplicand_0 * multiplicand_1 * const_0.into() + addend * const_1.into(); - let first_computed_output = first_multiplicand_0 * first_multiplicand_1 * const_0.into() - + first_addend * const_1.into(); - let second_computed_output = second_multiplicand_0 * second_multiplicand_1 * const_0.into() - + second_addend * const_1.into(); + constraints.extend((output - computed_output).to_basefield_array()); + } - let mut constraints = (first_output - first_computed_output) - .to_basefield_array() - .to_vec(); - constraints.extend((second_output - second_computed_output).to_basefield_array()); constraints } @@ -75,24 +60,18 @@ impl, const D: usize> Gate for ArithmeticExtensionGate let const_0 = vars.local_constants[0]; let const_1 = vars.local_constants[1]; - let first_multiplicand_0 = vars.get_local_ext(Self::wires_first_multiplicand_0()); - let first_multiplicand_1 = vars.get_local_ext(Self::wires_first_multiplicand_1()); - let first_addend = vars.get_local_ext(Self::wires_first_addend()); - let second_multiplicand_0 = vars.get_local_ext(Self::wires_second_multiplicand_0()); - let second_multiplicand_1 = vars.get_local_ext(Self::wires_second_multiplicand_1()); - let second_addend = vars.get_local_ext(Self::wires_second_addend()); - let first_output = vars.get_local_ext(Self::wires_first_output()); - let second_output = vars.get_local_ext(Self::wires_second_output()); + let mut constraints = Vec::new(); + for i in 0..NUM_ARITHMETIC_OPS { + let multiplicand_0 = vars.get_local_ext(Self::wires_ith_multiplicand_0(i)); + let multiplicand_1 = vars.get_local_ext(Self::wires_ith_multiplicand_1(i)); + let addend = vars.get_local_ext(Self::wires_ith_addend(i)); + let output = vars.get_local_ext(Self::wires_ith_output(i)); + let computed_output = + multiplicand_0 * multiplicand_1 * const_0.into() + addend * const_1.into(); - let first_computed_output = first_multiplicand_0 * first_multiplicand_1 * const_0.into() - + first_addend * const_1.into(); - let second_computed_output = second_multiplicand_0 * second_multiplicand_1 * const_0.into() - + second_addend * const_1.into(); + constraints.extend((output - computed_output).to_basefield_array()); + } - let mut constraints = (first_output - first_computed_output) - .to_basefield_array() - .to_vec(); - constraints.extend((second_output - second_computed_output).to_basefield_array()); constraints } @@ -104,34 +83,23 @@ impl, const D: usize> Gate for ArithmeticExtensionGate let const_0 = vars.local_constants[0]; let const_1 = vars.local_constants[1]; - let first_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_0()); - let first_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_1()); - let first_addend = vars.get_local_ext_algebra(Self::wires_first_addend()); - let second_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_0()); - let second_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_1()); - let second_addend = vars.get_local_ext_algebra(Self::wires_second_addend()); - let first_output = vars.get_local_ext_algebra(Self::wires_first_output()); - let second_output = vars.get_local_ext_algebra(Self::wires_second_output()); + let mut constraints = Vec::new(); + for i in 0..NUM_ARITHMETIC_OPS { + let multiplicand_0 = vars.get_local_ext_algebra(Self::wires_ith_multiplicand_0(i)); + let multiplicand_1 = vars.get_local_ext_algebra(Self::wires_ith_multiplicand_1(i)); + let addend = vars.get_local_ext_algebra(Self::wires_ith_addend(i)); + let output = vars.get_local_ext_algebra(Self::wires_ith_output(i)); + let computed_output = { + let mul = builder.mul_ext_algebra(multiplicand_0, multiplicand_1); + let scaled_mul = builder.scalar_mul_ext_algebra(const_0, mul); + let scaled_addend = builder.scalar_mul_ext_algebra(const_1, addend); + builder.add_ext_algebra(scaled_mul, scaled_addend) + }; - let first_computed_output = - builder.mul_ext_algebra(first_multiplicand_0, first_multiplicand_1); - let first_computed_output = builder.scalar_mul_ext_algebra(const_0, first_computed_output); - let first_scaled_addend = builder.scalar_mul_ext_algebra(const_1, first_addend); - let first_computed_output = - builder.add_ext_algebra(first_computed_output, first_scaled_addend); + let diff = builder.sub_ext_algebra(output, computed_output); + constraints.extend(diff.to_ext_target_array()); + } - let second_computed_output = - builder.mul_ext_algebra(second_multiplicand_0, second_multiplicand_1); - let second_computed_output = - builder.scalar_mul_ext_algebra(const_0, second_computed_output); - let second_scaled_addend = builder.scalar_mul_ext_algebra(const_1, second_addend); - let second_computed_output = - builder.add_ext_algebra(second_computed_output, second_scaled_addend); - - let diff_0 = builder.sub_ext_algebra(first_output, first_computed_output); - let diff_1 = builder.sub_ext_algebra(second_output, second_computed_output); - let mut constraints = diff_0.to_ext_target_array().to_vec(); - constraints.extend(diff_1.to_ext_target_array()); constraints } @@ -140,21 +108,21 @@ impl, const D: usize> Gate for ArithmeticExtensionGate gate_index: usize, local_constants: &[F], ) -> Vec>> { - let gen0 = ArithmeticExtensionGenerator0 { - gate_index, - const_0: local_constants[0], - const_1: local_constants[1], - }; - let gen1 = ArithmeticExtensionGenerator1 { - gate_index, - const_0: local_constants[0], - const_1: local_constants[1], - }; - vec![Box::new(gen0), Box::new(gen1)] + (0..NUM_ARITHMETIC_OPS) + .map(|i| { + let g: Box> = Box::new(ArithmeticExtensionGenerator { + gate_index, + const_0: local_constants[0], + const_1: local_constants[1], + i, + }); + g + }) + .collect::>() } fn num_wires(&self) -> usize { - 8 * D + NUM_ARITHMETIC_OPS * 4 * D } fn num_constants(&self) -> usize { @@ -166,27 +134,25 @@ impl, const D: usize> Gate for ArithmeticExtensionGate } fn num_constraints(&self) -> usize { - 2 * D + NUM_ARITHMETIC_OPS * D } } -struct ArithmeticExtensionGenerator0, const D: usize> { +#[derive(Clone)] +struct ArithmeticExtensionGenerator, const D: usize> { gate_index: usize, const_0: F, const_1: F, + i: usize, } -struct ArithmeticExtensionGenerator1, const D: usize> { - gate_index: usize, - const_0: F, - const_1: F, -} - -impl, const D: usize> SimpleGenerator for ArithmeticExtensionGenerator0 { +impl, const D: usize> SimpleGenerator for ArithmeticExtensionGenerator { fn dependencies(&self) -> Vec { - ArithmeticExtensionGate::::wires_first_multiplicand_0() - .chain(ArithmeticExtensionGate::::wires_first_multiplicand_1()) - .chain(ArithmeticExtensionGate::::wires_first_addend()) + ArithmeticExtensionGate::::wires_ith_multiplicand_0(self.i) + .chain(ArithmeticExtensionGate::::wires_ith_multiplicand_1( + self.i, + )) + .chain(ArithmeticExtensionGate::::wires_ith_addend(self.i)) .map(|i| Target::wire(self.gate_index, i)) .collect() } @@ -197,48 +163,17 @@ impl, const D: usize> SimpleGenerator for ArithmeticExtensio witness.get_extension_target(t) }; - let multiplicand_0 = - extract_extension(ArithmeticExtensionGate::::wires_first_multiplicand_0()); - let multiplicand_1 = - extract_extension(ArithmeticExtensionGate::::wires_first_multiplicand_1()); - let addend = extract_extension(ArithmeticExtensionGate::::wires_first_addend()); - - let output_target = ExtensionTarget::from_range( - self.gate_index, - ArithmeticExtensionGate::::wires_first_output(), + let multiplicand_0 = extract_extension( + ArithmeticExtensionGate::::wires_ith_multiplicand_0(self.i), ); - - let computed_output = - multiplicand_0 * multiplicand_1 * self.const_0.into() + addend * self.const_1.into(); - - out_buffer.set_extension_target(output_target, computed_output) - } -} - -impl, const D: usize> SimpleGenerator for ArithmeticExtensionGenerator1 { - fn dependencies(&self) -> Vec { - ArithmeticExtensionGate::::wires_second_multiplicand_0() - .chain(ArithmeticExtensionGate::::wires_second_multiplicand_1()) - .chain(ArithmeticExtensionGate::::wires_second_addend()) - .map(|i| Target::wire(self.gate_index, i)) - .collect() - } - - fn run_once(&self, witness: &PartialWitness, out_buffer: &mut GeneratedValues) { - let extract_extension = |range: Range| -> F::Extension { - let t = ExtensionTarget::from_range(self.gate_index, range); - witness.get_extension_target(t) - }; - - let multiplicand_0 = - extract_extension(ArithmeticExtensionGate::::wires_second_multiplicand_0()); - let multiplicand_1 = - extract_extension(ArithmeticExtensionGate::::wires_second_multiplicand_1()); - let addend = extract_extension(ArithmeticExtensionGate::::wires_second_addend()); + let multiplicand_1 = extract_extension( + ArithmeticExtensionGate::::wires_ith_multiplicand_1(self.i), + ); + let addend = extract_extension(ArithmeticExtensionGate::::wires_ith_addend(self.i)); let output_target = ExtensionTarget::from_range( self.gate_index, - ArithmeticExtensionGate::::wires_second_output(), + ArithmeticExtensionGate::::wires_ith_output(self.i), ); let computed_output = diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 003c9ab0..5e8540ae 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -139,7 +139,7 @@ impl, const D: usize, const R: usize> Gate for GMiMCGate< for r in 0..R { let active = r % W; - let cubing_input = state[active] + addition_buffer + self.constants[r].into(); + let cubing_input = state[active] + addition_buffer + self.constants[r]; let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)]; constraints.push(cubing_input - cubing_input_wire); let f = cubing_input_wire.cube(); @@ -160,8 +160,6 @@ impl, const D: usize, const R: usize> Gate for GMiMCGate< builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec> { - let one = builder.one_extension(); - let neg_one = builder.neg_one_extension(); let mut constraints = Vec::with_capacity(self.num_constraints()); let swap = vars.local_wires[Self::WIRE_SWAP]; @@ -197,18 +195,8 @@ impl, const D: usize, const R: usize> Gate for GMiMCGate< let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)]; constraints.push(builder.sub_extension(cubing_input, cubing_input_wire)); let f = builder.cube_extension(cubing_input_wire); - // addition_buffer += f - // state[active] -= f - (addition_buffer, state[active]) = builder.double_arithmetic_extension( - F::ONE, - F::ONE, - one, - addition_buffer, - f, - neg_one, - f, - state[active], - ); + addition_buffer = builder.add_extension(addition_buffer, f); + state[active] = builder.sub_extension(state[active], f); } for i in 0..W { diff --git a/src/iop/generator.rs b/src/iop/generator.rs index 6ab1b412..17567a4c 100644 --- a/src/iop/generator.rs +++ b/src/iop/generator.rs @@ -1,4 +1,3 @@ -use std::convert::identity; use std::fmt::Debug; use crate::field::extension_field::target::ExtensionTarget; @@ -75,11 +74,6 @@ pub(crate) fn generate_partial_witness( pending_generator_indices = next_pending_generator_indices; } - - assert!( - generator_is_expired.into_iter().all(identity), - "Some generators weren't run." - ); } /// A generator participates in the generation of the witness. diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index aa8998b6..573e0532 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -60,6 +60,10 @@ pub struct CircuitBuilder, const D: usize> { constants_to_targets: HashMap, targets_to_constants: HashMap, + + /// A map `(c0, c1) -> (g, i)` from constants `(c0,c1)` to an available arithmetic gate using + /// these constants with gate index `g` and already using `i` arithmetic operations. + pub(crate) free_arithmetic: HashMap<(F, F), (usize, usize)>, } impl, const D: usize> CircuitBuilder { @@ -76,6 +80,7 @@ impl, const D: usize> CircuitBuilder { generators: Vec::new(), constants_to_targets: HashMap::new(), targets_to_constants: HashMap::new(), + free_arithmetic: HashMap::new(), } } diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index 3b9becab..e4353c70 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -61,7 +61,7 @@ impl CircuitConfig { pub(crate) fn large_config() -> Self { Self { num_wires: 126, - num_routed_wires: 33, + num_routed_wires: 64, security_bits: 128, rate_bits: 3, num_challenges: 3, @@ -78,6 +78,7 @@ impl CircuitConfig { pub(crate) fn large_zk_config() -> Self { CircuitConfig { zero_knowledge: true, + cap_height: 1, fri_config: FriConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index 27e8f2fb..6789d114 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -37,7 +37,7 @@ impl, const D: usize> CircuitBuilder { self.constants(&inner_common_data.circuit_digest.elements), ); challenger.observe_hash(&digest); - challenger.observe_hash(&public_inputs_hash); + challenger.observe_hash(public_inputs_hash); challenger.observe_cap(&proof.wires_cap); let betas = challenger.get_n_challenges(self, num_challenges); @@ -420,25 +420,25 @@ mod tests { const D: usize = 4; let config = CircuitConfig { num_wires: 126, - num_routed_wires: 37, + num_routed_wires: 64, security_bits: 128, rate_bits: 3, num_challenges: 3, zero_knowledge: false, cap_height: 3, fri_config: FriConfig { - proof_of_work_bits: 1, - reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], - num_query_rounds: 40, + proof_of_work_bits: 20, + reduction_arity_bits: vec![3, 3, 3], + num_query_rounds: 27, }, }; let (proof_with_pis, vd, cd) = { let (proof_with_pis, vd, cd) = { let mut builder = CircuitBuilder::::new(config.clone()); let _two = builder.two(); - let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; + let mut _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; for _ in 0..10000 { - let _two = builder.mul(_two, _two); + _two = builder.mul(_two, _two); } let data = builder.build(); ( diff --git a/src/plonk/vanishing_poly.rs b/src/plonk/vanishing_poly.rs index a2a97d4b..6a282be9 100644 --- a/src/plonk/vanishing_poly.rs +++ b/src/plonk/vanishing_poly.rs @@ -1,5 +1,3 @@ -use num::Integer; - use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::Field; @@ -306,17 +304,8 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( // Holds `k[i] * x`. let mut s_ids = Vec::new(); - for j in 0..common_data.config.num_routed_wires / 2 { - let k_0 = builder.constant(common_data.k_is[2 * j]); - let k_0_ext = builder.convert_to_ext(k_0); - let k_1 = builder.constant(common_data.k_is[2 * j + 1]); - let k_1_ext = builder.convert_to_ext(k_1); - let tmp = builder.mul_two_extension(k_0_ext, x, k_1_ext, x); - s_ids.push(tmp.0); - s_ids.push(tmp.1); - } - if common_data.config.num_routed_wires.is_odd() { - let k = builder.constant(common_data.k_is[common_data.k_is.len() - 1]); + for j in 0..common_data.config.num_routed_wires { + let k = builder.constant(common_data.k_is[j]); let k_ext = builder.convert_to_ext(k); s_ids.push(builder.mul_extension(k_ext, x)); } diff --git a/src/util/reducing.rs b/src/util/reducing.rs index d2f4fcf2..ca0dd9e8 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -1,11 +1,8 @@ use std::borrow::Borrow; -use num::Integer; - use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, Frobenius}; use crate::field::field_types::Field; -use crate::gates::arithmetic::ArithmeticExtensionGate; use crate::gates::reducing::ReducingGate; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; @@ -164,40 +161,15 @@ impl ReducingFactorTarget { where F: Extendable, { - let zero = builder.zero_extension(); let l = terms.len(); self.count += l as u64; let mut terms_vec = terms.to_vec(); - // If needed, we pad the original vector so that it has even length. - if terms_vec.len().is_odd() { - terms_vec.push(zero); - } + let mut acc = terms_vec.pop().unwrap(); terms_vec.reverse(); - let mut acc = zero; - for pair in terms_vec.chunks(2) { - // We will route the output of the first arithmetic operation to the multiplicand of the - // second, i.e. we compute the following: - // out_0 = alpha acc + pair[0] - // acc' = out_1 = alpha out_0 + pair[1] - let gate = builder.num_gates(); - let out_0 = ExtensionTarget::from_range( - gate, - ArithmeticExtensionGate::::wires_first_output(), - ); - acc = builder - .double_arithmetic_extension( - F::ONE, - F::ONE, - self.base, - acc, - pair[0], - self.base, - out_0, - pair[1], - ) - .1; + for x in terms_vec { + acc = builder.mul_add_extension(self.base, acc, x); } acc } @@ -215,23 +187,6 @@ impl ReducingFactorTarget { builder.mul_extension(exp, x) } - /// Returns `(self.shift(x), a*b)`. - /// Used to take advantage of the second arithmetic operation in the `ArithmeticExtensionGate`. - pub fn shift_and_mul( - &mut self, - x: ExtensionTarget, - a: ExtensionTarget, - b: ExtensionTarget, - builder: &mut CircuitBuilder, - ) -> (ExtensionTarget, ExtensionTarget) - where - F: Extendable, - { - let exp = builder.exp_u64_extension(self.base, self.count); - self.count = 0; - builder.mul_two_extension(exp, x, a, b) - } - pub fn reset(&mut self) { self.count = 0; }