From f325586beb88c575918ba2dc99b4cb5ec7ee8104 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 14:58:41 +0200 Subject: [PATCH 01/13] Replace `exp_from_complement_bits` with simpler method --- src/fri/recursive_verifier.rs | 10 ++++++---- src/gadgets/arithmetic.rs | 21 --------------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 7592bc1f..60cb0b7c 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -25,18 +25,20 @@ impl, const D: usize> CircuitBuilder { last_evals: &[ExtensionTarget], beta: ExtensionTarget, ) -> ExtensionTarget { - debug_assert_eq!(last_evals.len(), 1 << arity_bits); + let arity = 1 << arity_bits; + debug_assert_eq!(last_evals.len(), arity); let g = F::primitive_root_of_unity(arity_bits); - let gt = self.constant(g); + let g_inv = g.exp((arity as u64) - 1); + let g_inv_t = self.constant(g_inv); // The evaluation vector needs to be reordered first. let mut evals = last_evals.to_vec(); reverse_index_bits_in_place(&mut evals); // Want `g^(arity - rev_old_x_index)` as in the out-of-circuit version. // Compute it as `g^(arity-1-rev_old_x_index) * g`, where the first term is gotten using two's complement. - let start = self.exp_from_complement_bits(gt, old_x_index_bits.iter().rev()); - let coset_start = self.mul_many(&[start, gt, x]); + let start = self.exp_from_bits(g_inv_t, old_x_index_bits.iter().rev()); + 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 points = g diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index cfeef82e..370f9900 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -188,27 +188,6 @@ impl, const D: usize> CircuitBuilder { product } - // TODO: Optimize this, maybe with a new gate. - // TODO: Test - /// Exponentiate `base` to the power of `2^bit_length-1-exponent`, given by its little-endian bits. - pub fn exp_from_complement_bits( - &mut self, - base: Target, - exponent_bits: impl Iterator>, - ) -> Target { - let mut current = base; - let one = self.one(); - let mut product = one; - - for bit in exponent_bits { - let multiplicand = self.select(*bit.borrow(), one, current); - product = self.mul(product, multiplicand); - current = self.mul(current, current); - } - - product - } - // TODO: Optimize this, maybe with a new gate. // TODO: Test /// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`. From 19140e39b21b2636c6d747cb79615ca4f148eda7 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 15:01:45 +0200 Subject: [PATCH 02/13] Update comment --- src/fri/recursive_verifier.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 60cb0b7c..262d91a2 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -35,8 +35,7 @@ impl, const D: usize> CircuitBuilder { // The evaluation vector needs to be reordered first. let mut evals = last_evals.to_vec(); reverse_index_bits_in_place(&mut evals); - // Want `g^(arity - rev_old_x_index)` as in the out-of-circuit version. - // Compute it as `g^(arity-1-rev_old_x_index) * g`, where the first term is gotten using two's complement. + // Want `g^(arity - rev_old_x_index)` as in the out-of-circuit version. Compute it as `(g^-1)^rev_old_x_index`. let start = self.exp_from_bits(g_inv_t, old_x_index_bits.iter().rev()); let coset_start = self.mul(start, x); From 0526a9e1490328d6f0681117814a1189b80e7aca Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 17:16:53 +0200 Subject: [PATCH 03/13] Working ReducingGate --- src/bin/bench_recursion.rs | 2 +- src/circuit_data.rs | 2 +- src/gates/mod.rs | 1 + src/gates/reducing.rs | 176 +++++++++++++++++++++++++++++++++++++ src/plonk_challenger.rs | 2 +- src/util/scaling.rs | 76 ++++++++++++++++ 6 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 src/gates/reducing.rs diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index 8e798f72..a34bfe2e 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -21,7 +21,7 @@ fn main() -> Result<()> { fn bench_prove, const D: usize>() -> Result<()> { let config = CircuitConfig { - num_wires: 134, + num_wires: 126, num_routed_wires: 33, security_bits: 128, rate_bits: 3, diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 787c446d..3087f566 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -57,7 +57,7 @@ impl CircuitConfig { pub(crate) fn large_config() -> Self { Self { num_wires: 126, - num_routed_wires: 34, + num_routed_wires: 33, security_bits: 128, rate_bits: 3, num_challenges: 3, diff --git a/src/gates/mod.rs b/src/gates/mod.rs index 441383ec..987a276d 100644 --- a/src/gates/mod.rs +++ b/src/gates/mod.rs @@ -11,6 +11,7 @@ pub mod insertion; pub mod interpolation; pub(crate) mod noop; pub(crate) mod public_input; +pub mod reducing; #[cfg(test)] mod gate_testing; diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs new file mode 100644 index 00000000..930f0456 --- /dev/null +++ b/src/gates/reducing.rs @@ -0,0 +1,176 @@ +use std::ops::Range; + +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::Extendable; +use crate::field::extension_field::FieldExtension; +use crate::gates::gate::Gate; +use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; +use crate::witness::PartialWitness; + +#[derive(Debug, Clone)] +pub struct ReducingGate { + pub num_coeffs: usize, +} + +impl ReducingGate { + pub fn new(num_coeffs: usize) -> Self { + Self { num_coeffs } + } + + 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 + } + pub const START_COEFFS: usize = 3 * D; + pub fn wires_coeffs(&self) -> Range { + Self::START_COEFFS..Self::START_COEFFS + self.num_coeffs + } + pub fn start_accs(&self) -> usize { + Self::START_COEFFS + self.num_coeffs + } + pub fn wires_accs(&self, i: usize) -> Range { + self.start_accs() + 4 * i..self.start_accs() + 4 * (i + 1) + } +} + +impl, const D: usize> Gate for ReducingGate { + fn id(&self) -> String { + format!("{:?}", self) + } + + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { + let output = vars.get_local_ext_algebra(Self::wires_output()); + let alpha = vars.get_local_ext_algebra(Self::wires_alpha()); + let old_acc = vars.get_local_ext_algebra(Self::wires_old_acc()); + let coeffs = self + .wires_coeffs() + .map(|i| vars.local_wires[i]) + .collect::>(); + let accs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext_algebra(self.wires_accs(i))) + .collect::>(); + + let mut constraints = Vec::new(); + let mut acc = old_acc; + for i in 0..self.num_coeffs { + constraints.push(acc * alpha + coeffs[i].into() - accs[i]); + acc = accs[i]; + } + + constraints.push(output - acc); + constraints + .into_iter() + .flat_map(|alg| alg.to_basefield_array()) + .collect() + } + + fn eval_unfiltered_recursively( + &self, + builder: &mut CircuitBuilder, + vars: EvaluationTargets, + ) -> Vec> { + todo!() + } + + fn generators( + &self, + gate_index: usize, + _local_constants: &[F], + ) -> Vec>> { + vec![Box::new(ReducingGenerator { + gate_index, + gate: self.clone(), + })] + } + + fn num_wires(&self) -> usize { + 3 * D + self.num_coeffs * (D + 1) + } + + fn num_constants(&self) -> usize { + 0 + } + + fn degree(&self) -> usize { + 2 + } + + fn num_constraints(&self) -> usize { + D * (self.num_coeffs + 1) + } +} + +struct ReducingGenerator { + gate_index: usize, + gate: ReducingGate, +} + +impl, const D: usize> SimpleGenerator for ReducingGenerator { + fn dependencies(&self) -> Vec { + ReducingGate::::wires_alpha() + .chain(ReducingGate::::wires_old_acc()) + .chain(self.gate.wires_coeffs()) + .map(|i| Target::wire(self.gate_index, i)) + .collect() + } + + fn run_once(&self, witness: &PartialWitness) -> 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(ReducingGate::::wires_alpha()); + let old_acc = extract_extension(ReducingGate::::wires_old_acc()); + let coeffs = witness.get_targets( + &self + .gate + .wires_coeffs() + .map(|i| Target::wire(self.gate_index, 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, ReducingGate::::wires_output()); + + let mut result = GeneratedValues::::with_capacity(self.gate.num_coeffs + 1); + let mut acc = old_acc; + for i in 0..self.gate.num_coeffs { + let computed_acc = acc * alpha + coeffs[i].into(); + result.set_extension_target(accs[i], computed_acc); + acc = computed_acc; + } + result.set_extension_target(output, acc); + + result + } +} + +#[cfg(test)] +mod tests { + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::extension_field::FieldExtension; + use crate::field::field::Field; + use crate::gates::gate::Gate; + use crate::gates::gate_testing::test_low_degree; + use crate::gates::reducing::ReducingGate; + use crate::proof::Hash; + use crate::vars::EvaluationVars; + + #[test] + fn low_degree() { + type F = CrandallField; + test_low_degree::(ReducingGate::new(22)); + } +} diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index f48cbbf1..4799007e 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -393,7 +393,7 @@ mod tests { } let config = CircuitConfig { - num_wires: 12 + 12 + 3 + 101, + num_wires: 12 + 12 + 1 + 101, num_routed_wires: 27, ..CircuitConfig::default() }; diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 5cbffb83..87d907c5 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -7,7 +7,9 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, Frobenius}; use crate::field::field::Field; use crate::gates::arithmetic::ArithmeticExtensionGate; +use crate::gates::reducing::ReducingGate; use crate::polynomial::polynomial::PolynomialCoeffs; +use crate::target::Target; /// When verifying the composition polynomial in FRI we have to compute sums of the form /// `(sum_0^k a^i * x_i)/d_0 + (sum_k^r a^i * y_i)/d_1` @@ -90,6 +92,47 @@ impl ReducingFactorTarget { Self { base, count: 0 } } + pub fn reduce_base( + &mut self, + terms: &[Target], + builder: &mut CircuitBuilder, + ) -> ExtensionTarget + where + F: Extendable, + { + let max_coeffs = 21; + let zero = builder.zero(); + let zero_ext = builder.zero_extension(); + let mut gate; + let mut gate_index; + let mut acc = zero_ext; + let mut reversed_terms = terms.to_vec(); + while reversed_terms.len() % max_coeffs != 0 { + reversed_terms.push(zero); + } + reversed_terms.reverse(); + for chunk in reversed_terms.chunks_exact(max_coeffs) { + gate = ReducingGate::new(max_coeffs); + gate_index = builder.add_gate(gate.clone(), Vec::new()); + + builder.route_extension( + self.base, + ExtensionTarget::from_range(gate_index, ReducingGate::::wires_alpha()), + ); + builder.route_extension( + acc, + ExtensionTarget::from_range(gate_index, ReducingGate::::wires_old_acc()), + ); + for (&t, c) in chunk.iter().zip(gate.wires_coeffs()) { + builder.route(t, Target::wire(gate_index, c)); + } + + acc = ExtensionTarget::from_range(gate_index, ReducingGate::::wires_output()); + } + + acc + } + /// Reduces a length `n` vector of `ExtensionTarget`s using `n/2` `ArithmeticExtensionGate`s. /// It does this by batching two steps of Horner's method in each gate. /// Here's an example with `n=4, alpha=2, D=1`: @@ -179,9 +222,37 @@ mod tests { use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::extension_field::FieldExtension; use crate::verifier::verify; use crate::witness::PartialWitness; + fn test_reduce_gadget_base(n: usize) -> Result<()> { + type F = CrandallField; + type FF = QuarticCrandallField; + const D: usize = 4; + + let config = CircuitConfig::large_config(); + + let mut builder = CircuitBuilder::::new(config); + + let alpha = FF::rand(); + let vs = F::rand_vec(n); + + let manual_reduce = ReducingFactor::new(alpha).reduce(vs.iter().map(|&v| FF::from(v))); + let manual_reduce = builder.constant_extension(manual_reduce); + + let mut alpha_t = ReducingFactorTarget::new(builder.constant_extension(alpha)); + let vs_t = vs.iter().map(|&v| builder.constant(v)).collect::>(); + let circuit_reduce = alpha_t.reduce_base(&vs_t, &mut builder); + + builder.assert_equal_extension(manual_reduce, circuit_reduce); + + let data = builder.build(); + let proof = data.prove(PartialWitness::new())?; + + verify(proof, &data.verifier_only, &data.common) + } + fn test_reduce_gadget(n: usize) -> Result<()> { type F = CrandallField; type FF = QuarticCrandallField; @@ -221,4 +292,9 @@ mod tests { fn test_reduce_gadget_odd() -> Result<()> { test_reduce_gadget(11) } + + #[test] + fn test_reduce_gadget_base_100() -> Result<()> { + test_reduce_gadget_base(100) + } } From ca540a847583a08b26ca6b305f3b5522ae35ed04 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 17:29:31 +0200 Subject: [PATCH 04/13] Working `fri_combine_initial` --- src/fri/recursive_verifier.rs | 8 ++++---- src/recursive_verifier.rs | 2 +- src/util/scaling.rs | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 7592bc1f..628b7861 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -197,9 +197,9 @@ impl, const D: usize> CircuitBuilder { &proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge) [common_data.partial_products_range()], ) - .map(|&e| self.convert_to_ext(e)) + .copied() .collect::>(); - let single_composition_eval = alpha.reduce(&single_evals, self); + let single_composition_eval = alpha.reduce_base(&single_evals, self); let single_numerator = self.sub_extension(single_composition_eval, precomputed_reduced_evals.single); let single_denominator = self.sub_extension(subgroup_x, zeta); @@ -212,9 +212,9 @@ impl, const D: usize> CircuitBuilder { .unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge) .iter() .take(common_data.zs_range().end) - .map(|&e| self.convert_to_ext(e)) + .copied() .collect::>(); - let zs_composition_eval = alpha.reduce(&zs_evals, self); + let zs_composition_eval = alpha.reduce_base(&zs_evals, self); let g = self.constant_extension(F::Extension::primitive_root_of_unity(degree_log)); let zeta_right = self.mul_extension(g, zeta); diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index cc92ccdb..c4d2cba0 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -381,7 +381,7 @@ mod tests { let mut builder = CircuitBuilder::::new(config.clone()); let _two = builder.two(); let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; - for _ in 0..5000 { + for _ in 0..10000 { let _two = builder.mul(_two, _two); } let data = builder.build(); diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 87d907c5..f69d6675 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -101,6 +101,7 @@ impl ReducingFactorTarget { F: Extendable, { let max_coeffs = 21; + self.count += terms.len() as u64; let zero = builder.zero(); let zero_ext = builder.zero_extension(); let mut gate; From c16d93ab334f80ab906a87be2380437c5ea6d96a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 17:31:00 +0200 Subject: [PATCH 05/13] scaling.rs -> reducing.rs --- src/fri/recursive_verifier.rs | 2 +- src/fri/verifier.rs | 2 +- src/polynomial/commitment.rs | 2 +- src/recursive_verifier.rs | 2 +- src/util/mod.rs | 2 +- src/util/{scaling.rs => reducing.rs} | 0 src/vanishing_poly.rs | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename src/util/{scaling.rs => reducing.rs} (100%) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 628b7861..50dded85 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -11,7 +11,7 @@ use crate::proof::{ FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, HashTarget, OpeningSetTarget, }; use crate::target::Target; -use crate::util::scaling::ReducingFactorTarget; +use crate::util::reducing::ReducingFactorTarget; use crate::util::{log2_strict, reverse_index_bits_in_place}; impl, const D: usize> CircuitBuilder { diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 27e775e6..8417dac1 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -10,7 +10,7 @@ use crate::merkle_proofs::verify_merkle_proof; use crate::plonk_challenger::Challenger; use crate::plonk_common::PlonkPolynomials; use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; -use crate::util::scaling::ReducingFactor; +use crate::util::reducing::ReducingFactor; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; /// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 356cd976..a2c9001b 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -15,7 +15,7 @@ use crate::plonk_common::PlonkPolynomials; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::{FriProof, FriProofTarget, Hash, HashTarget, OpeningSet, OpeningSetTarget}; use crate::timed; -use crate::util::scaling::ReducingFactor; +use crate::util::reducing::ReducingFactor; use crate::util::{log2_ceil, log2_strict, reverse_bits, reverse_index_bits_in_place, transpose}; /// Two (~64 bit) field elements gives ~128 bit security. diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index c4d2cba0..7cf37895 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -4,7 +4,7 @@ use crate::context; use crate::field::extension_field::Extendable; use crate::plonk_challenger::RecursiveChallenger; use crate::proof::{HashTarget, ProofWithPublicInputsTarget}; -use crate::util::scaling::ReducingFactorTarget; +use crate::util::reducing::ReducingFactorTarget; use crate::vanishing_poly::eval_vanishing_poly_recursively; use crate::vars::EvaluationTargets; diff --git a/src/util/mod.rs b/src/util/mod.rs index 83a97881..9176563a 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,6 +1,6 @@ pub mod marking; pub mod partial_products; -pub mod scaling; +pub mod reducing; pub(crate) mod timing; use crate::field::field::Field; diff --git a/src/util/scaling.rs b/src/util/reducing.rs similarity index 100% rename from src/util/scaling.rs rename to src/util/reducing.rs diff --git a/src/vanishing_poly.rs b/src/vanishing_poly.rs index 540ab86b..e3e4284c 100644 --- a/src/vanishing_poly.rs +++ b/src/vanishing_poly.rs @@ -9,7 +9,7 @@ use crate::plonk_common; use crate::plonk_common::{eval_l_1_recursively, ZeroPolyOnCoset}; use crate::target::Target; use crate::util::partial_products::{check_partial_products, check_partial_products_recursively}; -use crate::util::scaling::ReducingFactorTarget; +use crate::util::reducing::ReducingFactorTarget; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random From 5a16d7c5558df35c60bb079fbcfac10b9016327c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 17:35:23 +0200 Subject: [PATCH 06/13] Change number of coeffs supported in `ReducingGate` depending on config --- src/gates/reducing.rs | 4 ++++ src/util/reducing.rs | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs index 930f0456..65b09d60 100644 --- a/src/gates/reducing.rs +++ b/src/gates/reducing.rs @@ -20,6 +20,10 @@ impl ReducingGate { Self { num_coeffs } } + pub fn max_coeffs_len(num_wires: usize, num_routed_wires: usize) -> usize { + (num_routed_wires - 3 * D).min((num_wires - 3 * D) / (D + 1)) + } + pub fn wires_output() -> Range { 0..D } diff --git a/src/util/reducing.rs b/src/util/reducing.rs index f69d6675..ae15ef4b 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -100,7 +100,10 @@ impl ReducingFactorTarget { where F: Extendable, { - let max_coeffs = 21; + let max_coeffs_len = ReducingGate::::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(); @@ -108,12 +111,12 @@ impl ReducingFactorTarget { let mut gate_index; let mut acc = zero_ext; let mut reversed_terms = terms.to_vec(); - while reversed_terms.len() % max_coeffs != 0 { + while reversed_terms.len() % max_coeffs_len != 0 { reversed_terms.push(zero); } reversed_terms.reverse(); - for chunk in reversed_terms.chunks_exact(max_coeffs) { - gate = ReducingGate::new(max_coeffs); + for chunk in reversed_terms.chunks_exact(max_coeffs_len) { + gate = ReducingGate::new(max_coeffs_len); gate_index = builder.add_gate(gate.clone(), Vec::new()); builder.route_extension( From 2ea35bd9e4479d9f3f3c23326507c7d66312c3b4 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 17:38:24 +0200 Subject: [PATCH 07/13] Comments --- src/gates/reducing.rs | 1 + src/util/reducing.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs index 65b09d60..ebcd5cac 100644 --- a/src/gates/reducing.rs +++ b/src/gates/reducing.rs @@ -10,6 +10,7 @@ use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::witness::PartialWitness; +/// Computes `sum alpha^i c_i` for a vector `c_i` of `num_coeffs` elements of the base field. #[derive(Debug, Clone)] pub struct ReducingGate { pub num_coeffs: usize, diff --git a/src/util/reducing.rs b/src/util/reducing.rs index ae15ef4b..1b01763a 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -92,6 +92,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). pub fn reduce_base( &mut self, terms: &[Target], From 8f18089aac2dc01094d1db893e5d33ec2ec56135 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 18:06:14 +0200 Subject: [PATCH 08/13] Implement `eval_unfiltered_recursively` for `ReducingGate` --- src/field/extension_field/target.rs | 7 +++++++ src/gates/reducing.rs | 28 +++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 6083e2c4..97576ac6 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -115,6 +115,13 @@ impl, const D: usize> CircuitBuilder { arr[0] = t; ExtensionTarget(arr) } + + pub fn convert_to_ext_algebra(&mut self, et: ExtensionTarget) -> ExtensionAlgebraTarget { + let zero = self.zero_extension(); + let mut arr = [zero; D]; + arr[0] = et; + ExtensionAlgebraTarget(arr) + } } /// Flatten the slice by sending every extension target to its D-sized canonical representation. diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs index ebcd5cac..4c750bb9 100644 --- a/src/gates/reducing.rs +++ b/src/gates/reducing.rs @@ -82,7 +82,33 @@ impl, const D: usize> Gate for ReducingGate { builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec> { - todo!() + let output = vars.get_local_ext_algebra(Self::wires_output()); + let alpha = vars.get_local_ext_algebra(Self::wires_alpha()); + let old_acc = vars.get_local_ext_algebra(Self::wires_old_acc()); + let coeffs = self + .wires_coeffs() + .map(|i| vars.local_wires[i]) + .collect::>(); + let accs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext_algebra(self.wires_accs(i))) + .collect::>(); + + let mut constraints = Vec::new(); + let mut acc = old_acc; + for i in 0..self.num_coeffs { + let mut tmp = builder.mul_ext_algebra(acc, alpha); + let coeff = builder.convert_to_ext_algebra(coeffs[i]); + tmp = builder.add_ext_algebra(tmp, coeff); + tmp = builder.sub_ext_algebra(tmp, accs[i]); + constraints.push(tmp); + acc = accs[i]; + } + + constraints.push(builder.sub_ext_algebra(output, acc)); + constraints + .into_iter() + .flat_map(|alg| alg.to_ext_target_array()) + .collect() } fn generators( From c0f09591eed905bf2e6296942152b131967ebaa2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 18:24:09 +0200 Subject: [PATCH 09/13] Recursive recursive verifier test --- src/recursive_verifier.rs | 72 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 7cf37895..ef6b8cff 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -411,4 +411,76 @@ mod tests { verify(recursive_proof, &data.verifier_only, &data.common) } + + #[test] + #[ignore] + fn test_recursive_recursive_verifier() -> Result<()> { + env_logger::init(); + type F = CrandallField; + const D: usize = 4; + let config = CircuitConfig { + num_wires: 126, + num_routed_wires: 33, + security_bits: 128, + rate_bits: 3, + num_challenges: 3, + zero_knowledge: false, + fri_config: FriConfig { + proof_of_work_bits: 1, + reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], + num_query_rounds: 40, + }, + }; + 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]; + for _ in 0..10000 { + let _two = builder.mul(_two, _two); + } + let data = builder.build(); + ( + data.prove(PartialWitness::new())?, + data.verifier_only, + data.common, + ) + }; + verify(proof_with_pis.clone(), &vd, &cd)?; + + let mut builder = CircuitBuilder::::new(config.clone()); + let mut pw = PartialWitness::new(); + let pt = proof_to_proof_target(&proof_with_pis, &mut builder); + set_proof_target(&proof_with_pis, &pt, &mut pw); + + let inner_data = VerifierCircuitTarget { + constants_sigmas_root: builder.add_virtual_hash(), + }; + pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); + + builder.add_recursive_verifier(pt, &config, &inner_data, &cd); + + let data = builder.build(); + let recursive_proof = data.prove(pw)?; + (recursive_proof, data.verifier_only, data.common) + }; + + verify(proof_with_pis.clone(), &vd, &cd)?; + let mut builder = CircuitBuilder::::new(config.clone()); + let mut pw = PartialWitness::new(); + let pt = proof_to_proof_target(&proof_with_pis, &mut builder); + set_proof_target(&proof_with_pis, &pt, &mut pw); + + let inner_data = VerifierCircuitTarget { + constants_sigmas_root: builder.add_virtual_hash(), + }; + pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); + + builder.add_recursive_verifier(pt, &config, &inner_data, &cd); + + builder.print_gate_counts(0); + let data = builder.build(); + let recursive_proof = data.prove(pw)?; + verify(recursive_proof, &data.verifier_only, &data.common) + } } From d509f03b1bb0eb5d6525016d59e0f2e65ea34573 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Jul 2021 18:32:59 +0200 Subject: [PATCH 10/13] Implement `eval_unfiltered_base` --- src/gates/reducing.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs index 4c750bb9..f85bb3c2 100644 --- a/src/gates/reducing.rs +++ b/src/gates/reducing.rs @@ -77,6 +77,32 @@ impl, const D: usize> Gate for ReducingGate { .collect() } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let output = vars.get_local_ext(Self::wires_output()); + let alpha = vars.get_local_ext(Self::wires_alpha()); + let old_acc = vars.get_local_ext(Self::wires_old_acc()); + let coeffs = self + .wires_coeffs() + .map(|i| vars.local_wires[i]) + .collect::>(); + let accs = (0..self.num_coeffs) + .map(|i| vars.get_local_ext(self.wires_accs(i))) + .collect::>(); + + let mut constraints = Vec::new(); + let mut acc = old_acc; + for i in 0..self.num_coeffs { + constraints.push(acc * alpha + coeffs[i].into() - accs[i]); + acc = accs[i]; + } + + constraints.push(output - acc); + constraints + .into_iter() + .flat_map(|alg| alg.to_basefield_array()) + .collect() + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, From deea1c979bdb936448e97ffe96b302b17aa17792 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sun, 25 Jul 2021 18:12:26 +0200 Subject: [PATCH 11/13] PR feedback --- src/gates/reducing.rs | 21 ++++++++------------- src/util/reducing.rs | 7 ++----- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs index f85bb3c2..9404cf93 100644 --- a/src/gates/reducing.rs +++ b/src/gates/reducing.rs @@ -34,15 +34,19 @@ impl ReducingGate { pub fn wires_old_acc() -> Range { 2 * D..3 * D } - pub const START_COEFFS: usize = 3 * D; + const START_COEFFS: usize = 3 * D; pub fn wires_coeffs(&self) -> Range { Self::START_COEFFS..Self::START_COEFFS + self.num_coeffs } - pub fn start_accs(&self) -> usize { + fn start_accs(&self) -> usize { Self::START_COEFFS + self.num_coeffs } - pub fn wires_accs(&self, i: usize) -> Range { - self.start_accs() + 4 * i..self.start_accs() + 4 * (i + 1) + 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) } } @@ -70,7 +74,6 @@ impl, const D: usize> Gate for ReducingGate { acc = accs[i]; } - constraints.push(output - acc); constraints .into_iter() .flat_map(|alg| alg.to_basefield_array()) @@ -96,7 +99,6 @@ impl, const D: usize> Gate for ReducingGate { acc = accs[i]; } - constraints.push(output - acc); constraints .into_iter() .flat_map(|alg| alg.to_basefield_array()) @@ -130,7 +132,6 @@ impl, const D: usize> Gate for ReducingGate { acc = accs[i]; } - constraints.push(builder.sub_ext_algebra(output, acc)); constraints .into_iter() .flat_map(|alg| alg.to_ext_target_array()) @@ -216,14 +217,8 @@ impl, const D: usize> SimpleGenerator for ReducingGenerator< #[cfg(test)] mod tests { use crate::field::crandall_field::CrandallField; - use crate::field::extension_field::quartic::QuarticCrandallField; - use crate::field::extension_field::FieldExtension; - use crate::field::field::Field; - use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; use crate::gates::reducing::ReducingGate; - use crate::proof::Hash; - use crate::vars::EvaluationVars; #[test] fn low_degree() { diff --git a/src/util/reducing.rs b/src/util/reducing.rs index 1b01763a..6a4a1168 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -108,8 +108,6 @@ impl ReducingFactorTarget { self.count += terms.len() as u64; let zero = builder.zero(); let zero_ext = builder.zero_extension(); - let mut gate; - let mut gate_index; let mut acc = zero_ext; let mut reversed_terms = terms.to_vec(); while reversed_terms.len() % max_coeffs_len != 0 { @@ -117,8 +115,8 @@ impl ReducingFactorTarget { } reversed_terms.reverse(); for chunk in reversed_terms.chunks_exact(max_coeffs_len) { - gate = ReducingGate::new(max_coeffs_len); - gate_index = builder.add_gate(gate.clone(), Vec::new()); + let gate = ReducingGate::new(max_coeffs_len); + let gate_index = builder.add_gate(gate.clone(), Vec::new()); builder.route_extension( self.base, @@ -227,7 +225,6 @@ mod tests { use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; - use crate::field::extension_field::FieldExtension; use crate::verifier::verify; use crate::witness::PartialWitness; From 3fc02c76bc882c5d1c50a446be1a52f7b4830efd Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 25 Jul 2021 09:34:51 -0700 Subject: [PATCH 12/13] Couple fixes to ReducingGate (#128) --- src/gates/gate_testing.rs | 6 ++++++ src/gates/reducing.rs | 9 +++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/gates/gate_testing.rs b/src/gates/gate_testing.rs index b71d1509..4a6c80df 100644 --- a/src/gates/gate_testing.rs +++ b/src/gates/gate_testing.rs @@ -36,6 +36,12 @@ pub(crate) fn test_low_degree, G: Gate, const D: usize>(g .map(|p| p.degree()) .collect::>(); + assert_eq!( + constraint_eval_degrees.len(), + gate.num_constraints(), + "eval should return num_constraints() constraints" + ); + let expected_eval_degree = WITNESS_DEGREE * gate.degree(); assert!( diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs index 9404cf93..0129a156 100644 --- a/src/gates/reducing.rs +++ b/src/gates/reducing.rs @@ -22,7 +22,7 @@ impl ReducingGate { } pub fn max_coeffs_len(num_wires: usize, num_routed_wires: usize) -> usize { - (num_routed_wires - 3 * D).min((num_wires - 3 * D) / (D + 1)) + (num_routed_wires - 3 * D).min((num_wires - 2 * D) / (D + 1)) } pub fn wires_output() -> Range { @@ -56,7 +56,6 @@ impl, const D: usize> Gate for ReducingGate { } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { - let output = vars.get_local_ext_algebra(Self::wires_output()); let alpha = vars.get_local_ext_algebra(Self::wires_alpha()); let old_acc = vars.get_local_ext_algebra(Self::wires_old_acc()); let coeffs = self @@ -81,7 +80,6 @@ impl, const D: usize> Gate for ReducingGate { } fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { - let output = vars.get_local_ext(Self::wires_output()); let alpha = vars.get_local_ext(Self::wires_alpha()); let old_acc = vars.get_local_ext(Self::wires_old_acc()); let coeffs = self @@ -110,7 +108,6 @@ impl, const D: usize> Gate for ReducingGate { builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec> { - let output = vars.get_local_ext_algebra(Self::wires_output()); let alpha = vars.get_local_ext_algebra(Self::wires_alpha()); let old_acc = vars.get_local_ext_algebra(Self::wires_old_acc()); let coeffs = self @@ -150,7 +147,7 @@ impl, const D: usize> Gate for ReducingGate { } fn num_wires(&self) -> usize { - 3 * D + self.num_coeffs * (D + 1) + 2 * D + self.num_coeffs * (D + 1) } fn num_constants(&self) -> usize { @@ -162,7 +159,7 @@ impl, const D: usize> Gate for ReducingGate { } fn num_constraints(&self) -> usize { - D * (self.num_coeffs + 1) + D * self.num_coeffs } } From 9081ae7337e8f0c6554f03c2cd49b367f4968835 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 26 Jul 2021 16:21:14 -0700 Subject: [PATCH 13/13] Reduce noise in FRI logging (#129) * Reduce noise in FRI logging Previously, all logs related to gate counts were at the `Debug` log level. This PR gives us more flexibility to adjust the log levels of particular scopes. In particular, our circuit checks 40 FRI queries, and we log a bunch of steps for each query, creating a lot of noise. With this change, we log just a single FRI query at the `Debug` level, and demote others to the `Trace` level. With `RUST_LOG=debug`, our logs now look like ``` [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] 17631 gates to root [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | 8 gates to observe proof and generates challenges [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | 4150 gates to evaluate the vanishing polynomial at our challenge point, zeta. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | 3184 gates to evaluate gate constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 227 gates to evaluate InterpolationGate { num_points: 4, _phantom: PhantomData } constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 867 gates to evaluate GMiMCGate { ... } constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 576 gates to evaluate BaseSumGate { num_limbs: 63 } + Base: 2 constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 78 gates to evaluate ArithmeticExtensionGate constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 288 gates to evaluate BaseSumGate { num_limbs: 31 } + Base: 2 constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 115 gates to evaluate InsertionGate { vec_size: 3, _phantom: PhantomData } constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 26 gates to evaluate BaseSumGate { num_limbs: 2 } + Base: 2 constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 633 gates to evaluate ReducingGate { num_coeffs: 21 } constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 4 gates to evaluate ConstantGate constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 11 gates to evaluate PublicInputGate constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 2 gates to evaluate NoopGate constraints [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | 16 gates to check vanishing and quotient polynomials. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | 13336 gates to verify FRI proof [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | 6 gates to recover the random betas used in the FRI reductions. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | 4 gates to check PoW [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | 104 gates to precompute reduced evaluations [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | 330 gates to verify one (of 40) query rounds [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 95 gates to check FRI initial proof [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | | 22 gates to verify 0'th initial Merkle proof [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | | 33 gates to verify 1'th initial Merkle proof [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | | 20 gates to verify 2'th initial Merkle proof [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | | 20 gates to verify 3'th initial Merkle proof [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 34 gates to compute x from its index [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 32 gates to combine initial oracles [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 17 gates to verify FRI round Merkle proof. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 10 gates to infer evaluation using interpolation [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 15 gates to verify FRI round Merkle proof. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 10 gates to infer evaluation using interpolation [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 13 gates to verify FRI round Merkle proof. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 10 gates to infer evaluation using interpolation [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 11 gates to verify FRI round Merkle proof. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 10 gates to infer evaluation using interpolation [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 9 gates to verify FRI round Merkle proof. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 10 gates to infer evaluation using interpolation [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 7 gates to verify FRI round Merkle proof. [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 10 gates to infer final evaluation using interpolation [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | | 8 gates to evaluate final polynomial ``` This bit corresponds to the single FRI query being shown: ``` [2021-07-26T21:07:45Z DEBUG plonky2::context_tree] | | 330 gates to verify one (of 40) query rounds ``` * Minor cleanup * Address feedback --- src/circuit_builder.rs | 4 ++-- src/context_tree.rs | 28 +++++++++++++++++----- src/fri/recursive_verifier.rs | 45 +++++++++++++++++++++++------------ src/polynomial/commitment.rs | 4 ++-- src/recursive_verifier.rs | 8 +++---- src/vanishing_poly.rs | 6 ++--- 6 files changed, 63 insertions(+), 32 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 5d286a46..57f5b7ac 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -301,8 +301,8 @@ impl, const D: usize> CircuitBuilder { self.targets_to_constants.get(&target).cloned() } - pub fn push_context(&mut self, ctx: &str) { - self.context_log.push(ctx, self.num_gates()); + pub fn push_context(&mut self, level: log::Level, ctx: &str) { + self.context_log.push(ctx, level, self.num_gates()); } pub fn pop_context(&mut self) { diff --git a/src/context_tree.rs b/src/context_tree.rs index 6482f71d..7ec5214c 100644 --- a/src/context_tree.rs +++ b/src/context_tree.rs @@ -1,9 +1,11 @@ -use log::debug; +use log::{log, Level}; /// The hierarchy of contexts, and the gate count contributed by each one. Useful for debugging. pub(crate) struct ContextTree { /// The name of this scope. name: String, + /// The level at which to log this scope and its children. + level: log::Level, /// The gate count when this scope was created. enter_gate_count: usize, /// The gate count when this scope was destroyed, or None if it has not yet been destroyed. @@ -16,6 +18,7 @@ impl ContextTree { pub fn new() -> Self { Self { name: "root".to_string(), + level: Level::Debug, enter_gate_count: 0, exit_gate_count: None, children: vec![], @@ -43,18 +46,22 @@ impl ContextTree { } } - pub fn push(&mut self, ctx: &str, current_gate_count: usize) { + pub fn push(&mut self, ctx: &str, mut level: log::Level, current_gate_count: usize) { assert!(self.is_open()); + // We don't want a scope's log level to be stronger than that of its parent. + level = level.max(self.level); + if let Some(last_child) = self.children.last_mut() { if last_child.is_open() { - last_child.push(ctx, current_gate_count); + last_child.push(ctx, level, current_gate_count); return; } } self.children.push(ContextTree { name: ctx.to_string(), + level, enter_gate_count: current_gate_count, exit_gate_count: None, children: vec![], @@ -83,6 +90,7 @@ impl ContextTree { pub fn filter(&self, current_gate_count: usize, min_delta: usize) -> Self { Self { name: self.name.clone(), + level: self.level, enter_gate_count: self.enter_gate_count, exit_gate_count: self.exit_gate_count, children: self @@ -100,7 +108,8 @@ impl ContextTree { fn print_helper(&self, current_gate_count: usize, depth: usize) { let prefix = "| ".repeat(depth); - debug!( + log!( + self.level, "{}{} gates to {}", prefix, self.gate_count_delta(current_gate_count), @@ -114,9 +123,16 @@ impl ContextTree { /// Creates a named scope; useful for debugging. #[macro_export] -macro_rules! context { +macro_rules! with_context { + ($builder:expr, $level:expr, $ctx:expr, $exp:expr) => {{ + $builder.push_context($level, $ctx); + let res = $exp; + $builder.pop_context(); + res + }}; + // If no context is specified, default to Debug. ($builder:expr, $ctx:expr, $exp:expr) => {{ - $builder.push_context($ctx); + $builder.push_context(log::Level::Debug, $ctx); let res = $exp; $builder.pop_context(); res diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index ed4d3750..0c256ae8 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -1,6 +1,5 @@ use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CommonCircuitData; -use crate::context; use crate::field::extension_field::target::{flatten_target, ExtensionTarget}; use crate::field::extension_field::Extendable; use crate::field::field::Field; @@ -13,6 +12,7 @@ use crate::proof::{ use crate::target::Target; use crate::util::reducing::ReducingFactorTarget; use crate::util::{log2_strict, reverse_index_bits_in_place}; +use crate::with_context; impl, const D: usize> CircuitBuilder { /// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity @@ -93,7 +93,7 @@ impl, const D: usize> CircuitBuilder { // Size of the LDE domain. let n = proof.final_poly.len() << (total_arities + config.rate_bits); - let betas = context!( + let betas = with_context!( self, "recover the random betas used in the FRI reductions.", proof @@ -107,7 +107,7 @@ impl, const D: usize> CircuitBuilder { ); challenger.observe_extension_elements(&proof.final_poly.0); - context!( + with_context!( self, "check PoW", self.fri_verify_proof_of_work(proof, challenger, &config.fri_config) @@ -124,12 +124,27 @@ impl, const D: usize> CircuitBuilder { "Number of reductions should be non-zero." ); - let precomputed_reduced_evals = - PrecomputedReducedEvalsTarget::from_os_and_alpha(os, alpha, self); + let precomputed_reduced_evals = with_context!( + self, + "precompute reduced evaluations", + PrecomputedReducedEvalsTarget::from_os_and_alpha(os, alpha, self) + ); + for (i, round_proof) in proof.query_round_proofs.iter().enumerate() { - context!( + // To minimize noise in our logs, we will only record a context for a single FRI query. + // The very first query will have some extra gates due to constants being registered, so + // the second query is a better representative. + let level = if i == 1 { + log::Level::Debug + } else { + log::Level::Trace + }; + + let num_queries = proof.query_round_proofs.len(); + with_context!( self, - &format!("verify {}'th FRI query", i), + level, + &format!("verify one (of {}) query rounds", num_queries), self.fri_verifier_query_round( zeta, alpha, @@ -158,7 +173,7 @@ impl, const D: usize> CircuitBuilder { .zip(initial_merkle_roots) .enumerate() { - context!( + with_context!( self, &format!("verify {}'th initial Merkle proof", i), self.verify_merkle_proof(evals.clone(), x_index_bits, root, merkle_proof) @@ -256,7 +271,7 @@ impl, const D: usize> CircuitBuilder { let x_index = challenger.get_challenge(self); let mut x_index_bits = self.low_bits(x_index, n_log, 64); let mut domain_size = n; - context!( + with_context!( self, "check FRI initial proof", self.fri_verify_initial_proof( @@ -268,7 +283,7 @@ impl, const D: usize> CircuitBuilder { let mut old_x_index_bits = Vec::new(); // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. - let mut subgroup_x = context!(self, "compute x from its index", { + let mut subgroup_x = with_context!(self, "compute x from its index", { let g = self.constant(F::MULTIPLICATIVE_GROUP_GENERATOR); let phi = self.constant(F::primitive_root_of_unity(n_log)); @@ -280,7 +295,7 @@ impl, const D: usize> CircuitBuilder { for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() { let next_domain_size = domain_size >> arity_bits; let e_x = if i == 0 { - context!( + with_context!( self, "combine initial oracles", self.fri_combine_initial( @@ -295,7 +310,7 @@ impl, const D: usize> CircuitBuilder { } else { let last_evals = &evaluations[i - 1]; // Infer P(y) from {P(x)}_{x^arity=y}. - context!( + with_context!( self, "infer evaluation using interpolation", self.compute_evaluation( @@ -313,7 +328,7 @@ impl, const D: usize> CircuitBuilder { old_x_index_bits = x_index_bits; let low_x_index = self.le_sum(old_x_index_bits.iter()); evals = self.insert(low_x_index, e_x, evals); - context!( + with_context!( self, "verify FRI round Merkle proof.", self.verify_merkle_proof( @@ -335,7 +350,7 @@ impl, const D: usize> CircuitBuilder { let last_evals = evaluations.last().unwrap(); let final_arity_bits = *config.reduction_arity_bits.last().unwrap(); - let purported_eval = context!( + let purported_eval = with_context!( self, "infer final evaluation using interpolation", self.compute_evaluation( @@ -350,7 +365,7 @@ impl, const D: usize> CircuitBuilder { // Final check of FRI. After all the reductions, we check that the final polynomial is equal // to the one sent by the prover. - let eval = context!( + let eval = with_context!( self, "evaluate final polynomial", proof.final_poly.eval_scalar(self, subgroup_x) diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index a2c9001b..a307ba2c 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,7 +4,6 @@ use serde::{Deserialize, Serialize}; use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CommonCircuitData; -use crate::context; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field::Field; @@ -17,6 +16,7 @@ use crate::proof::{FriProof, FriProofTarget, Hash, HashTarget, OpeningSet, Openi use crate::timed; use crate::util::reducing::ReducingFactor; use crate::util::{log2_ceil, log2_strict, reverse_bits, reverse_index_bits_in_place, transpose}; +use crate::with_context; /// Two (~64 bit) field elements gives ~128 bit security. pub const SALT_SIZE: usize = 2; @@ -283,7 +283,7 @@ impl OpeningProofTarget { let alpha = challenger.get_extension_challenge(builder); - context!( + with_context!( builder, "verify FRI proof", builder.verify_fri_proof( diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index ef6b8cff..9e96be60 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -1,12 +1,12 @@ use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; -use crate::context; use crate::field::extension_field::Extendable; use crate::plonk_challenger::RecursiveChallenger; use crate::proof::{HashTarget, ProofWithPublicInputsTarget}; use crate::util::reducing::ReducingFactorTarget; use crate::vanishing_poly::eval_vanishing_poly_recursively; use crate::vars::EvaluationTargets; +use crate::with_context; const MIN_WIRES: usize = 120; // TODO: Double check. const MIN_ROUTED_WIRES: usize = 28; // TODO: Double check. @@ -35,7 +35,7 @@ impl, const D: usize> CircuitBuilder { let mut challenger = RecursiveChallenger::new(self); let (betas, gammas, alphas, zeta) = - context!(self, "observe proof and generates challenges", { + with_context!(self, "observe proof and generates challenges", { // Observe the instance. let digest = HashTarget::from_vec( self.constants(&inner_common_data.circuit_digest.elements), @@ -69,7 +69,7 @@ impl, const D: usize> CircuitBuilder { let partial_products = &proof.openings.partial_products; let zeta_pow_deg = self.exp_power_of_2_extension(zeta, inner_common_data.degree_bits); - let vanishing_polys_zeta = context!( + let vanishing_polys_zeta = with_context!( self, "evaluate the vanishing polynomial at our challenge point, zeta.", eval_vanishing_poly_recursively( @@ -88,7 +88,7 @@ impl, const D: usize> CircuitBuilder { ) ); - context!(self, "check vanishing and quotient polynomials.", { + with_context!(self, "check vanishing and quotient polynomials.", { let quotient_polys_zeta = &proof.openings.quotient_polys; let mut scale = ReducingFactorTarget::new(zeta_pow_deg); let z_h_zeta = self.sub_extension(zeta_pow_deg, one); diff --git a/src/vanishing_poly.rs b/src/vanishing_poly.rs index e3e4284c..6101a9fb 100644 --- a/src/vanishing_poly.rs +++ b/src/vanishing_poly.rs @@ -1,6 +1,5 @@ use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CommonCircuitData; -use crate::context; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field::Field; @@ -11,6 +10,7 @@ use crate::target::Target; use crate::util::partial_products::{check_partial_products, check_partial_products_recursively}; use crate::util::reducing::ReducingFactorTarget; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; +use crate::with_context; /// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random /// linear combination of gate constraints, plus some other terms relating to the permutation @@ -236,7 +236,7 @@ pub fn evaluate_gate_constraints_recursively, const D: usize>( ) -> Vec> { let mut constraints = vec![builder.zero_extension(); num_gate_constraints]; for gate in gates { - let gate_constraints = context!( + let gate_constraints = with_context!( builder, &format!("evaluate {} constraints", gate.gate.0.id()), gate.gate @@ -270,7 +270,7 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( let max_degree = common_data.quotient_degree_factor; let (num_prods, final_num_prod) = common_data.num_partial_products; - let constraint_terms = context!( + let constraint_terms = with_context!( builder, "evaluate gate constraints", evaluate_gate_constraints_recursively(