From 72ef58c19d4b2c537fa9ff23008b5e16b1ea62b9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 12 Nov 2021 18:24:08 +0100 Subject: [PATCH 1/7] Add ReducingExtGate --- src/gates/mod.rs | 1 + src/gates/reducing_extension.rs | 222 ++++++++++++++++++++++++++++++++ src/util/reducing.rs | 55 ++++++-- 3 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 src/gates/reducing_extension.rs diff --git a/src/gates/mod.rs b/src/gates/mod.rs index b1a6028e..da301c62 100644 --- a/src/gates/mod.rs +++ b/src/gates/mod.rs @@ -19,6 +19,7 @@ pub(crate) mod poseidon_mds; pub(crate) mod public_input; pub mod random_access; pub mod reducing; +pub mod reducing_extension; pub mod subtraction_u32; pub mod switch; diff --git a/src/gates/reducing_extension.rs b/src/gates/reducing_extension.rs new file mode 100644 index 00000000..93c981a6 --- /dev/null +++ b/src/gates/reducing_extension.rs @@ -0,0 +1,222 @@ +use std::ops::Range; + +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::Extendable; +use crate::field::extension_field::FieldExtension; +use crate::field::field_types::RichField; +use crate::gates::gate::Gate; +use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use crate::iop::target::Target; +use crate::iop::witness::{PartialWitness, PartitionWitness, Witness}; +use crate::plonk::circuit_builder::CircuitBuilder; +use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; + +/// Computes `sum alpha^i c_i` for a vector `c_i` of `num_coeffs` elements of the extension field. +#[derive(Debug, Clone)] +pub struct ReducingExtGate { + pub num_coeffs: usize, +} + +impl ReducingExtGate { + pub fn new(num_coeffs: usize) -> Self { + Self { num_coeffs } + } + + pub fn max_coeffs_len(num_wires: usize, num_routed_wires: usize) -> usize { + ((num_routed_wires - 3 * D) / D).min((num_wires - 2 * D) / (D * 2)) + } + + pub fn wires_output() -> Range { + 0..D + } + pub fn wires_alpha() -> Range { + D..2 * D + } + pub fn wires_old_acc() -> Range { + 2 * D..3 * D + } + const START_COEFFS: usize = 3 * D; + pub fn wires_coeff(i: usize) -> Range { + Self::START_COEFFS + i * D..Self::START_COEFFS + (i + 1) * D + } + fn start_accs(&self) -> usize { + Self::START_COEFFS + self.num_coeffs * D + } + fn wires_accs(&self, i: usize) -> Range { + if i == self.num_coeffs - 1 { + // The last accumulator is the output. + return Self::wires_output(); + } + self.start_accs() + D * i..self.start_accs() + D * (i + 1) + } +} + +impl, const D: usize> Gate for ReducingExtGate { + fn id(&self) -> String { + format!("{:?}", self) + } + + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { + let alpha = vars.get_local_ext_algebra(Self::wires_alpha()); + let old_acc = vars.get_local_ext_algebra(Self::wires_old_acc()); + let coeffs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext_algebra(Self::wires_coeff(i))) + .collect::>(); + let accs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext_algebra(self.wires_accs(i))) + .collect::>(); + + let mut constraints = Vec::with_capacity(>::num_constraints(self)); + let mut acc = old_acc; + for i in 0..self.num_coeffs { + constraints.push(acc * alpha + coeffs[i] - accs[i]); + acc = accs[i]; + } + + constraints + .into_iter() + .flat_map(|alg| alg.to_basefield_array()) + .collect() + } + + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let alpha = vars.get_local_ext(Self::wires_alpha()); + let old_acc = vars.get_local_ext(Self::wires_old_acc()); + let coeffs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext(Self::wires_coeff(i))) + .collect::>(); + let accs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext(self.wires_accs(i))) + .collect::>(); + + let mut constraints = Vec::with_capacity(>::num_constraints(self)); + let mut acc = old_acc; + for i in 0..self.num_coeffs { + constraints.extend((acc * alpha + coeffs[i] - accs[i]).to_basefield_array()); + acc = accs[i]; + } + + constraints + } + + fn eval_unfiltered_recursively( + &self, + builder: &mut CircuitBuilder, + vars: EvaluationTargets, + ) -> Vec> { + let alpha = vars.get_local_ext_algebra(Self::wires_alpha()); + let old_acc = vars.get_local_ext_algebra(Self::wires_old_acc()); + let coeffs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext_algebra(Self::wires_coeff(i))) + .collect::>(); + let accs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext_algebra(self.wires_accs(i))) + .collect::>(); + + let mut constraints = Vec::with_capacity(>::num_constraints(self)); + let mut acc = old_acc; + for i in 0..self.num_coeffs { + let coeff = coeffs[i]; + let mut tmp = builder.mul_add_ext_algebra(acc, alpha, coeff); + tmp = builder.sub_ext_algebra(tmp, accs[i]); + constraints.push(tmp); + acc = accs[i]; + } + + constraints + .into_iter() + .flat_map(|alg| alg.to_ext_target_array()) + .collect() + } + + fn generators( + &self, + gate_index: usize, + _local_constants: &[F], + ) -> Vec>> { + vec![Box::new( + ReducingGenerator { + gate_index, + gate: self.clone(), + } + .adapter(), + )] + } + + fn num_wires(&self) -> usize { + 2 * D + 2 * D * self.num_coeffs + } + + fn num_constants(&self) -> usize { + 0 + } + + fn degree(&self) -> usize { + 2 + } + + fn num_constraints(&self) -> usize { + D * self.num_coeffs + } +} + +#[derive(Debug)] +struct ReducingGenerator { + gate_index: usize, + gate: ReducingExtGate, +} + +impl, const D: usize> SimpleGenerator for ReducingGenerator { + fn dependencies(&self) -> Vec { + ReducingExtGate::::wires_alpha() + .chain(ReducingExtGate::::wires_old_acc()) + .chain((0..self.gate.num_coeffs).flat_map(|i| ReducingExtGate::::wires_coeff(i))) + .map(|i| Target::wire(self.gate_index, i)) + .collect() + } + + fn run_once(&self, witness: &PartitionWitness, 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 alpha = extract_extension(ReducingExtGate::::wires_alpha()); + let old_acc = extract_extension(ReducingExtGate::::wires_old_acc()); + let coeffs = (0..self.gate.num_coeffs) + .map(|i| extract_extension(ReducingExtGate::::wires_coeff(i))) + .collect::>(); + let accs = (0..self.gate.num_coeffs) + .map(|i| ExtensionTarget::from_range(self.gate_index, self.gate.wires_accs(i))) + .collect::>(); + let output = + ExtensionTarget::from_range(self.gate_index, ReducingExtGate::::wires_output()); + + let mut acc = old_acc; + for i in 0..self.gate.num_coeffs { + let computed_acc = acc * alpha + coeffs[i]; + out_buffer.set_extension_target(accs[i], computed_acc); + acc = computed_acc; + } + out_buffer.set_extension_target(output, acc); + } +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + + use crate::field::goldilocks_field::GoldilocksField; + use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; + use crate::gates::reducing_extension::ReducingExtGate; + + #[test] + fn low_degree() { + test_low_degree::(ReducingExtGate::new(22)); + } + + #[test] + fn eval_fns() -> Result<()> { + test_eval_fns::(ReducingExtGate::new(22)) + } +} diff --git a/src/util/reducing.rs b/src/util/reducing.rs index 3e00602c..ab3e2771 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -4,6 +4,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::{Field, RichField}; use crate::gates::reducing::ReducingGate; +use crate::gates::reducing_extension::ReducingExtGate; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::polynomial::polynomial::PolynomialCoeffs; @@ -145,16 +146,52 @@ impl ReducingFactorTarget { where F: RichField + Extendable, { - let l = terms.len(); - self.count += l as u64; - - let mut terms_vec = terms.to_vec(); - let mut acc = builder.zero_extension(); - terms_vec.reverse(); - - for x in terms_vec { - acc = builder.mul_add_extension(self.base, acc, x); + // let l = terms.len(); + // self.count += l as u64; + // + // let mut terms_vec = terms.to_vec(); + // let mut acc = builder.zero_extension(); + // terms_vec.reverse(); + // + // for x in terms_vec { + // acc = builder.mul_add_extension(self.base, acc, x); + // } + // acc + let max_coeffs_len = ReducingExtGate::::max_coeffs_len( + builder.config.num_wires, + builder.config.num_routed_wires, + ); + self.count += terms.len() as u64; + let zero = builder.zero(); + let zero_ext = builder.zero_extension(); + let mut acc = zero_ext; + let mut reversed_terms = terms.to_vec(); + while reversed_terms.len() % max_coeffs_len != 0 { + reversed_terms.push(zero_ext); } + reversed_terms.reverse(); + for chunk in reversed_terms.chunks_exact(max_coeffs_len) { + let gate = ReducingExtGate::new(max_coeffs_len); + let gate_index = builder.add_gate(gate.clone(), Vec::new()); + + builder.connect_extension( + self.base, + ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_alpha()), + ); + builder.connect_extension( + acc, + ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_old_acc()), + ); + for (i, &t) in chunk.iter().enumerate() { + builder.connect_extension( + t, + ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_coeff(i)), + ); + } + + acc = ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_output()); + } + acc } From 66719b0cfc2ef935c539eed293341247e8af5650 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 15 Nov 2021 10:33:27 +0100 Subject: [PATCH 2/7] Remove comments --- src/util/reducing.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/util/reducing.rs b/src/util/reducing.rs index ab3e2771..12be80f6 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -146,17 +146,6 @@ impl ReducingFactorTarget { where F: RichField + Extendable, { - // let l = terms.len(); - // self.count += l as u64; - // - // let mut terms_vec = terms.to_vec(); - // let mut acc = builder.zero_extension(); - // terms_vec.reverse(); - // - // for x in terms_vec { - // acc = builder.mul_add_extension(self.base, acc, x); - // } - // acc let max_coeffs_len = ReducingExtGate::::max_coeffs_len( builder.config.num_wires, builder.config.num_routed_wires, From a54db66f68ef58bd2a7802af05fad2b217db2c02 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 15 Nov 2021 11:38:48 +0100 Subject: [PATCH 3/7] Use arithmetic gate for small reductions --- src/gates/reducing_extension.rs | 34 ++++++++------- src/util/reducing.rs | 77 ++++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 26 deletions(-) diff --git a/src/gates/reducing_extension.rs b/src/gates/reducing_extension.rs index 93c981a6..9ee2134f 100644 --- a/src/gates/reducing_extension.rs +++ b/src/gates/reducing_extension.rs @@ -13,11 +13,11 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// Computes `sum alpha^i c_i` for a vector `c_i` of `num_coeffs` elements of the extension field. #[derive(Debug, Clone)] -pub struct ReducingExtGate { +pub struct ReducingExtensionGate { pub num_coeffs: usize, } -impl ReducingExtGate { +impl ReducingExtensionGate { pub fn new(num_coeffs: usize) -> Self { Self { num_coeffs } } @@ -51,7 +51,7 @@ impl ReducingExtGate { } } -impl, const D: usize> Gate for ReducingExtGate { +impl, const D: usize> Gate for ReducingExtensionGate { fn id(&self) -> String { format!("{:?}", self) } @@ -163,14 +163,16 @@ impl, const D: usize> Gate for ReducingExtGat #[derive(Debug)] struct ReducingGenerator { gate_index: usize, - gate: ReducingExtGate, + gate: ReducingExtensionGate, } impl, const D: usize> SimpleGenerator for ReducingGenerator { fn dependencies(&self) -> Vec { - ReducingExtGate::::wires_alpha() - .chain(ReducingExtGate::::wires_old_acc()) - .chain((0..self.gate.num_coeffs).flat_map(|i| ReducingExtGate::::wires_coeff(i))) + ReducingExtensionGate::::wires_alpha() + .chain(ReducingExtensionGate::::wires_old_acc()) + .chain( + (0..self.gate.num_coeffs).flat_map(|i| ReducingExtensionGate::::wires_coeff(i)), + ) .map(|i| Target::wire(self.gate_index, i)) .collect() } @@ -181,16 +183,18 @@ impl, const D: usize> SimpleGenerator for ReducingGenerator< witness.get_extension_target(t) }; - let alpha = extract_extension(ReducingExtGate::::wires_alpha()); - let old_acc = extract_extension(ReducingExtGate::::wires_old_acc()); + let alpha = extract_extension(ReducingExtensionGate::::wires_alpha()); + let old_acc = extract_extension(ReducingExtensionGate::::wires_old_acc()); let coeffs = (0..self.gate.num_coeffs) - .map(|i| extract_extension(ReducingExtGate::::wires_coeff(i))) + .map(|i| extract_extension(ReducingExtensionGate::::wires_coeff(i))) .collect::>(); let accs = (0..self.gate.num_coeffs) .map(|i| ExtensionTarget::from_range(self.gate_index, self.gate.wires_accs(i))) .collect::>(); - let output = - ExtensionTarget::from_range(self.gate_index, ReducingExtGate::::wires_output()); + let output = ExtensionTarget::from_range( + self.gate_index, + ReducingExtensionGate::::wires_output(), + ); let mut acc = old_acc; for i in 0..self.gate.num_coeffs { @@ -208,15 +212,15 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::gates::reducing_extension::ReducingExtGate; + use crate::gates::reducing_extension::ReducingExtensionGate; #[test] fn low_degree() { - test_low_degree::(ReducingExtGate::new(22)); + test_low_degree::(ReducingExtensionGate::new(22)); } #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(ReducingExtGate::new(22)) + test_eval_fns::(ReducingExtensionGate::new(22)) } } diff --git a/src/util/reducing.rs b/src/util/reducing.rs index 12be80f6..f2cd3d55 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -3,8 +3,9 @@ use std::borrow::Borrow; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::{Field, RichField}; +use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::reducing::ReducingGate; -use crate::gates::reducing_extension::ReducingExtGate; +use crate::gates::reducing_extension::ReducingExtensionGate; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::polynomial::polynomial::PolynomialCoeffs; @@ -94,7 +95,7 @@ impl ReducingFactorTarget { Self { base, count: 0 } } - /// Reduces a length `n` vector of `Target`s using `n/21` `ReducingGate`s (with 33 routed wires and 126 wires). + /// Reduces a vector of `Target`s using `ReducingGate`s. pub fn reduce_base( &mut self, terms: &[Target], @@ -103,11 +104,16 @@ impl ReducingFactorTarget { where F: RichField + Extendable, { + let l = terms.len(); + // For small reductions, use an arithmetic gate. + if l - 1 <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops { + return self.reduce_base_arithmetic(terms, builder); + } let max_coeffs_len = ReducingGate::::max_coeffs_len( builder.config.num_wires, builder.config.num_routed_wires, ); - self.count += terms.len() as u64; + self.count += l as u64; let zero = builder.zero(); let zero_ext = builder.zero_extension(); let mut acc = zero_ext; @@ -138,6 +144,26 @@ impl ReducingFactorTarget { acc } + /// Reduces a vector of `Target`s using `ArithmeticGate`s. + fn reduce_base_arithmetic( + &mut self, + terms: &[Target], + builder: &mut CircuitBuilder, + ) -> ExtensionTarget + where + F: RichField + Extendable, + { + self.count += terms.len() as u64; + terms + .iter() + .rev() + .fold(builder.zero_extension(), |acc, &t| { + let et = builder.convert_to_ext(t); + builder.mul_add_extension(self.base, acc, et) + }) + } + + /// Reduces a vector of `ExtensionTarget`s using `ReducingExtensionGate`s. pub fn reduce( &mut self, terms: &[ExtensionTarget], // Could probably work with a `DoubleEndedIterator` too. @@ -146,12 +172,16 @@ impl ReducingFactorTarget { where F: RichField + Extendable, { - let max_coeffs_len = ReducingExtGate::::max_coeffs_len( + let l = terms.len(); + // For small reductions, use an arithmetic gate. + if l - 1 <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops { + return self.reduce_arithmetic(terms, builder); + } + let max_coeffs_len = ReducingExtensionGate::::max_coeffs_len( builder.config.num_wires, builder.config.num_routed_wires, ); - self.count += terms.len() as u64; - let zero = builder.zero(); + self.count += l as u64; let zero_ext = builder.zero_extension(); let mut acc = zero_ext; let mut reversed_terms = terms.to_vec(); @@ -160,30 +190,55 @@ impl ReducingFactorTarget { } reversed_terms.reverse(); for chunk in reversed_terms.chunks_exact(max_coeffs_len) { - let gate = ReducingExtGate::new(max_coeffs_len); + let gate = ReducingExtensionGate::new(max_coeffs_len); let gate_index = builder.add_gate(gate.clone(), Vec::new()); builder.connect_extension( self.base, - ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_alpha()), + ExtensionTarget::from_range(gate_index, ReducingExtensionGate::::wires_alpha()), ); builder.connect_extension( acc, - ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_old_acc()), + ExtensionTarget::from_range( + gate_index, + ReducingExtensionGate::::wires_old_acc(), + ), ); for (i, &t) in chunk.iter().enumerate() { builder.connect_extension( t, - ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_coeff(i)), + ExtensionTarget::from_range( + gate_index, + ReducingExtensionGate::::wires_coeff(i), + ), ); } - acc = ExtensionTarget::from_range(gate_index, ReducingExtGate::::wires_output()); + acc = + ExtensionTarget::from_range(gate_index, ReducingExtensionGate::::wires_output()); } acc } + /// Reduces a vector of `ExtensionTarget`s using `ArithmeticGate`s. + fn reduce_arithmetic( + &mut self, + terms: &[ExtensionTarget], + builder: &mut CircuitBuilder, + ) -> ExtensionTarget + where + F: RichField + Extendable, + { + self.count += terms.len() as u64; + terms + .iter() + .rev() + .fold(builder.zero_extension(), |acc, &et| { + builder.mul_add_extension(self.base, acc, et) + }) + } + pub fn shift( &mut self, x: ExtensionTarget, From f787c5385f1591cd23c59ebd450b243270052ed3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 15 Nov 2021 11:50:27 +0100 Subject: [PATCH 4/7] Simplify --- src/util/reducing.rs | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/util/reducing.rs b/src/util/reducing.rs index f2cd3d55..f10f412d 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -105,10 +105,16 @@ impl ReducingFactorTarget { F: RichField + Extendable, { let l = terms.len(); + // For small reductions, use an arithmetic gate. if l - 1 <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops { - return self.reduce_base_arithmetic(terms, builder); + let terms_ext = terms + .iter() + .map(|&t| builder.convert_to_ext(t)) + .collect::>(); + return self.reduce_arithmetic(&terms_ext, builder); } + let max_coeffs_len = ReducingGate::::max_coeffs_len( builder.config.num_wires, builder.config.num_routed_wires, @@ -144,25 +150,6 @@ impl ReducingFactorTarget { acc } - /// Reduces a vector of `Target`s using `ArithmeticGate`s. - fn reduce_base_arithmetic( - &mut self, - terms: &[Target], - builder: &mut CircuitBuilder, - ) -> ExtensionTarget - where - F: RichField + Extendable, - { - self.count += terms.len() as u64; - terms - .iter() - .rev() - .fold(builder.zero_extension(), |acc, &t| { - let et = builder.convert_to_ext(t); - builder.mul_add_extension(self.base, acc, et) - }) - } - /// Reduces a vector of `ExtensionTarget`s using `ReducingExtensionGate`s. pub fn reduce( &mut self, @@ -173,10 +160,12 @@ impl ReducingFactorTarget { F: RichField + Extendable, { let l = terms.len(); + // For small reductions, use an arithmetic gate. if l - 1 <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops { return self.reduce_arithmetic(terms, builder); } + let max_coeffs_len = ReducingExtensionGate::::max_coeffs_len( builder.config.num_wires, builder.config.num_routed_wires, From 3efe2068bc99703e033f75ee34145fc102ebe44b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 15 Nov 2021 11:59:54 +0100 Subject: [PATCH 5/7] Minor --- src/gates/reducing_extension.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/gates/reducing_extension.rs b/src/gates/reducing_extension.rs index 9ee2134f..99d40fba 100644 --- a/src/gates/reducing_extension.rs +++ b/src/gates/reducing_extension.rs @@ -7,7 +7,7 @@ use crate::field::field_types::RichField; use crate::gates::gate::Gate; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::iop::target::Target; -use crate::iop::witness::{PartialWitness, PartitionWitness, Witness}; +use crate::iop::witness::{PartitionWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; @@ -170,9 +170,7 @@ impl, const D: usize> SimpleGenerator for ReducingGenerator< fn dependencies(&self) -> Vec { ReducingExtensionGate::::wires_alpha() .chain(ReducingExtensionGate::::wires_old_acc()) - .chain( - (0..self.gate.num_coeffs).flat_map(|i| ReducingExtensionGate::::wires_coeff(i)), - ) + .chain((0..self.gate.num_coeffs).flat_map(ReducingExtensionGate::::wires_coeff)) .map(|i| Target::wire(self.gate_index, i)) .collect() } From 49e4307820bb298e9b1bcbff2a8ca91905b5bf23 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 15 Nov 2021 13:35:21 +0100 Subject: [PATCH 6/7] Comments + test for reducing 100 extension elements --- src/gates/reducing_extension.rs | 16 +++++++--------- src/util/reducing.rs | 5 +++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/gates/reducing_extension.rs b/src/gates/reducing_extension.rs index 99d40fba..532b484f 100644 --- a/src/gates/reducing_extension.rs +++ b/src/gates/reducing_extension.rs @@ -23,6 +23,8 @@ impl ReducingExtensionGate { } pub fn max_coeffs_len(num_wires: usize, num_routed_wires: usize) -> usize { + // `3*D` routed wires are used for the output, alpha and old accumulator. + // Need `num_coeffs*D` routed wires for coeffs, and `(num_coeffs-1)*D` wires for accumulators. ((num_routed_wires - 3 * D) / D).min((num_wires - 2 * D) / (D * 2)) } @@ -43,6 +45,7 @@ impl ReducingExtensionGate { Self::START_COEFFS + self.num_coeffs * D } fn wires_accs(&self, i: usize) -> Range { + debug_assert!(i < self.num_coeffs); if i == self.num_coeffs - 1 { // The last accumulator is the output. return Self::wires_output(); @@ -176,23 +179,19 @@ impl, const D: usize> SimpleGenerator for ReducingGenerator< } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let extract_extension = |range: Range| -> F::Extension { + let local_extension = |range: Range| -> F::Extension { let t = ExtensionTarget::from_range(self.gate_index, range); witness.get_extension_target(t) }; - let alpha = extract_extension(ReducingExtensionGate::::wires_alpha()); - let old_acc = extract_extension(ReducingExtensionGate::::wires_old_acc()); + let alpha = local_extension(ReducingExtensionGate::::wires_alpha()); + let old_acc = local_extension(ReducingExtensionGate::::wires_old_acc()); let coeffs = (0..self.gate.num_coeffs) - .map(|i| extract_extension(ReducingExtensionGate::::wires_coeff(i))) + .map(|i| local_extension(ReducingExtensionGate::::wires_coeff(i))) .collect::>(); let accs = (0..self.gate.num_coeffs) .map(|i| ExtensionTarget::from_range(self.gate_index, self.gate.wires_accs(i))) .collect::>(); - let output = ExtensionTarget::from_range( - self.gate_index, - ReducingExtensionGate::::wires_output(), - ); let mut acc = old_acc; for i in 0..self.gate.num_coeffs { @@ -200,7 +199,6 @@ impl, const D: usize> SimpleGenerator for ReducingGenerator< out_buffer.set_extension_target(accs[i], computed_acc); acc = computed_acc; } - out_buffer.set_extension_target(output, acc); } } diff --git a/src/util/reducing.rs b/src/util/reducing.rs index f10f412d..1cddc3e7 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -330,4 +330,9 @@ mod tests { fn test_reduce_gadget_base_100() -> Result<()> { test_reduce_gadget_base(100) } + + #[test] + fn test_reduce_gadget_100() -> Result<()> { + test_reduce_gadget(100) + } } From 799ff26e71c03aec171fa0eb94abec8e11e3549e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 15 Nov 2021 19:46:28 +0100 Subject: [PATCH 7/7] Avoid underflow when checking the length of `terms` --- src/util/reducing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/reducing.rs b/src/util/reducing.rs index 1cddc3e7..f700a6ff 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -107,7 +107,7 @@ impl ReducingFactorTarget { let l = terms.len(); // For small reductions, use an arithmetic gate. - if l - 1 <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops { + if l <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops + 1 { let terms_ext = terms .iter() .map(|&t| builder.convert_to_ext(t)) @@ -162,7 +162,7 @@ impl ReducingFactorTarget { let l = terms.len(); // For small reductions, use an arithmetic gate. - if l - 1 <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops { + if l <= ArithmeticExtensionGate::::new_from_config(&builder.config).num_ops + 1 { return self.reduce_arithmetic(terms, builder); }