From 73ab11f4203dde237d3749d32d26d10b7ea48993 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 13 Aug 2021 11:35:20 +0200 Subject: [PATCH 1/9] More arithmetic optimizations --- src/fri/recursive_verifier.rs | 66 +++++++++++++++++++++++++---------- src/util/reducing.rs | 18 ++++++++-- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 1e028255..0e7fa381 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -139,7 +139,13 @@ impl, const D: usize> CircuitBuilder { let precomputed_reduced_evals = with_context!( self, "precompute reduced evaluations", - PrecomputedReducedEvalsTarget::from_os_and_alpha(os, alpha, self) + PrecomputedReducedEvalsTarget::from_os_and_alpha( + os, + alpha, + common_data.degree_bits, + zeta, + self + ) ); for (i, round_proof) in proof.query_round_proofs.iter().enumerate() { @@ -204,8 +210,8 @@ impl, const D: usize> CircuitBuilder { &mut self, proof: &FriInitialTreeProofTarget, alpha: ExtensionTarget, - zeta: ExtensionTarget, subgroup_x: Target, + vanish_zeta: ExtensionTarget, precomputed_reduced_evals: PrecomputedReducedEvalsTarget, common_data: &CommonCircuitData, ) -> ExtensionTarget { @@ -218,7 +224,6 @@ impl, const D: usize> CircuitBuilder { - config.rate_bits ); let subgroup_x = self.convert_to_ext(subgroup_x); - let vanish_zeta = self.sub_extension(subgroup_x, zeta); let mut alpha = ReducingFactorTarget::new(alpha); let mut sum = self.zero_extension(); @@ -255,19 +260,19 @@ impl, const D: usize> CircuitBuilder { .collect::>(); 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); - let interpol_val = self.interpolate2( - [ - (zeta, precomputed_reduced_evals.zs), - (zeta_right, precomputed_reduced_evals.zs_right), - ], - subgroup_x, + let interpol_val = self.mul_add_extension( + vanish_zeta, + 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, zeta_right); - let zs_denominator = self.mul_extension(vanish_zeta, vanish_zeta_right); - sum = alpha.shift(sum, self); + 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); sum = self.div_add_extension(zs_numerator, zs_denominator, sum); sum @@ -307,12 +312,25 @@ impl, const D: usize> CircuitBuilder { ); // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. - let mut subgroup_x = with_context!(self, "compute x from its index", { - let g = self.constant(F::MULTIPLICATIVE_GROUP_GENERATOR); + let (mut subgroup_x, vanish_zeta) = with_context!(self, "compute x from its index", { + let g = self.constant(F::coset_shift()); let phi = self.constant(F::primitive_root_of_unity(n_log)); let phi = self.exp_from_bits(phi, x_index_bits.iter().rev()); - self.mul(g, phi) + let g_ext = self.convert_to_ext(g); + let phi_ext = self.convert_to_ext(phi); + let zero = self.zero_extension(); + 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) }); // old_eval is the last derived evaluation; it will be checked for consistency with its @@ -323,8 +341,8 @@ impl, const D: usize> CircuitBuilder { self.fri_combine_initial( &round_proof.initial_trees_proof, alpha, - zeta, subgroup_x, + vanish_zeta, precomputed_reduced_evals, common_data, ) @@ -393,12 +411,16 @@ struct PrecomputedReducedEvalsTarget { pub single: ExtensionTarget, pub zs: ExtensionTarget, pub zs_right: ExtensionTarget, + pub slope: ExtensionTarget, + pub zeta_right: ExtensionTarget, } impl PrecomputedReducedEvalsTarget { fn from_os_and_alpha>( os: &OpeningSetTarget, alpha: ExtensionTarget, + degree_log: usize, + zeta: ExtensionTarget, builder: &mut CircuitBuilder, ) -> Self { let mut alpha = ReducingFactorTarget::new(alpha); @@ -416,10 +438,16 @@ impl PrecomputedReducedEvalsTarget { let zs = alpha.reduce(&os.plonk_zs, builder); let zs_right = alpha.reduce(&os.plonk_zs_right, builder); + 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); + Self { single, zs, zs_right, + slope: builder.div_extension(numerator, denominator), + zeta_right, } } } diff --git a/src/util/reducing.rs b/src/util/reducing.rs index ce6827ba..8e8fa661 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -211,9 +211,23 @@ impl ReducingFactorTarget { F: Extendable, { let exp = builder.exp_u64_extension(self.base, self.count); - let tmp = builder.mul_extension(exp, x); self.count = 0; - tmp + builder.mul_extension(exp, x) + } + + 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) { From 9547aa63829576d8a77dbced77766f71661b8a42 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 13 Aug 2021 14:30:48 +0200 Subject: [PATCH 2/9] minor --- src/plonk/vanishing_poly.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plonk/vanishing_poly.rs b/src/plonk/vanishing_poly.rs index e2180552..a2a97d4b 100644 --- a/src/plonk/vanishing_poly.rs +++ b/src/plonk/vanishing_poly.rs @@ -363,8 +363,9 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( .chunks(max_degree) .zip(partial_product_check.iter_mut()) .for_each(|(d, q)| { - let tmp = builder.mul_many_extension(d); - *q = builder.mul_extension(*q, tmp); + let mut v = d.to_vec(); + v.push(*q); + *q = builder.mul_many_extension(&v); }); vanishing_partial_products_terms.extend(partial_product_check); From 43641174cbe4cc3eccad7a101c0c6157e9fb6388 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 13 Aug 2021 18:00:40 +0200 Subject: [PATCH 3/9] Comments --- src/fri/recursive_verifier.rs | 1 + src/util/reducing.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 0e7fa381..046a54ae 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -320,6 +320,7 @@ impl, const D: usize> CircuitBuilder { 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, diff --git a/src/util/reducing.rs b/src/util/reducing.rs index 8e8fa661..d2f4fcf2 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -215,6 +215,8 @@ 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, From 08f0e0ff552326b3b47c1ea0a6495dbd130ee861 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Fri, 13 Aug 2021 19:36:21 -0700 Subject: [PATCH 4/9] Remove unnecessary checks They're out of date, and checked elsewhere --- src/plonk/recursive_verifier.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index 3ab1cdec..ea35d505 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -9,9 +9,6 @@ use crate::plonk::vars::EvaluationTargets; use crate::util::reducing::ReducingFactorTarget; use crate::with_context; -const MIN_WIRES: usize = 120; // TODO: Double check. -const MIN_ROUTED_WIRES: usize = 28; // TODO: Double check. - impl, const D: usize> CircuitBuilder { /// Recursively verifies an inner proof. pub fn add_recursive_verifier( @@ -21,8 +18,6 @@ impl, const D: usize> CircuitBuilder { inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) { - assert!(self.config.num_wires >= MIN_WIRES); - assert!(self.config.num_wires >= MIN_ROUTED_WIRES); let ProofWithPublicInputsTarget { proof, public_inputs, From 8aaa9401acc7c668fea0eaaa92c31e03c0150266 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 14 Aug 2021 11:48:13 +0200 Subject: [PATCH 5/9] Add comment for slope --- src/fri/recursive_verifier.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 046a54ae..503cdaf6 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -412,6 +412,7 @@ 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, } From 9c42fef99757b542e899b47df9d618c0eee24e6d Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sat, 14 Aug 2021 08:47:03 -0700 Subject: [PATCH 6/9] Little refactor (#178) --- src/fri/mod.rs | 27 --------------------- src/fri/recursive_verifier.rs | 6 ++--- src/fri/verifier.rs | 8 +++---- src/gadgets/split_join.rs | 45 +---------------------------------- src/gates/exponentiation.rs | 4 ++-- src/hash/merkle_tree.rs | 6 +++++ src/plonk/circuit_builder.rs | 6 +---- 7 files changed, 17 insertions(+), 85 deletions(-) diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 29d99d61..55a41abd 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -4,10 +4,6 @@ pub mod prover; pub mod recursive_verifier; pub mod verifier; -/// Somewhat arbitrary. Smaller values will increase delta, but with diminishing returns, -/// while increasing L, potentially requiring more challenge points. -const EPSILON: f64 = 0.01; - #[derive(Debug, Clone, Eq, PartialEq)] pub struct FriConfig { pub proof_of_work_bits: u32, @@ -23,26 +19,3 @@ pub struct FriConfig { pub cap_height: usize, } - -fn fri_delta(rate_log: usize, conjecture: bool) -> f64 { - let rate = (1 << rate_log) as f64; - if conjecture { - // See Conjecture 2.3 in DEEP-FRI. - 1.0 - rate - EPSILON - } else { - // See the Johnson radius. - 1.0 - rate.sqrt() - EPSILON - } -} - -fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 { - let rate = (1 << rate_log) as f64; - if conjecture { - // See Conjecture 2.3 in DEEP-FRI. - // We assume the conjecture holds with a constant of 1 (as do other STARK implementations). - (codeword_len as f64) / EPSILON - } else { - // See the Johnson bound. - 1.0 / (2.0 * EPSILON * rate.sqrt()) - } -} diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 503cdaf6..a8bd5d94 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -22,18 +22,18 @@ impl, const D: usize> CircuitBuilder { x: Target, x_index_within_coset_bits: &[Target], arity_bits: usize, - last_evals: &[ExtensionTarget], + evals: &[ExtensionTarget], beta: ExtensionTarget, ) -> ExtensionTarget { let arity = 1 << arity_bits; - debug_assert_eq!(last_evals.len(), arity); + debug_assert_eq!(evals.len(), arity); let g = F::primitive_root_of_unity(arity_bits); 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(); + let mut evals = evals.to_vec(); reverse_index_bits_in_place(&mut evals); // Want `g^(arity - rev_x_index_within_coset)` as in the out-of-circuit version. Compute it // as `(g^-1)^rev_x_index_within_coset`. diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 63359cd4..ff5dc87d 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -21,24 +21,24 @@ fn compute_evaluation, const D: usize>( x: F, x_index_within_coset: usize, arity_bits: usize, - last_evals: &[F::Extension], + evals: &[F::Extension], beta: F::Extension, ) -> F::Extension { let arity = 1 << arity_bits; - debug_assert_eq!(last_evals.len(), arity); + debug_assert_eq!(evals.len(), arity); let g = F::primitive_root_of_unity(arity_bits); // The evaluation vector needs to be reordered first. - let mut evals = last_evals.to_vec(); + let mut evals = evals.to_vec(); reverse_index_bits_in_place(&mut evals); let rev_x_index_within_coset = reverse_bits(x_index_within_coset, arity_bits); let coset_start = x * g.exp((arity - rev_x_index_within_coset) as u64); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g .powers() + .map(|y| (coset_start * y).into()) .zip(evals) - .map(|(y, e)| ((coset_start * y).into(), e)) .collect::>(); let barycentric_weights = barycentric_weights(&points); interpolate(&points, beta, &barycentric_weights) diff --git a/src/gadgets/split_join.rs b/src/gadgets/split_join.rs index 45422d5d..1fe25dbe 100644 --- a/src/gadgets/split_join.rs +++ b/src/gadgets/split_join.rs @@ -1,29 +1,13 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::gates::base_sum::BaseSumGate; -use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use crate::iop::generator::{GeneratedValues, SimpleGenerator}; use crate::iop::target::Target; -use crate::iop::wire::Wire; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::util::ceil_div_usize; impl, const D: usize> CircuitBuilder { - /// Split the given integer into a list of virtual targets, where each one represents a bit of - /// the integer, with little-endian ordering. - /// - /// Note that this only handles witness generation; it does not enforce that the decomposition - /// is correct. The output should be treated as a "purported" decomposition which must be - /// enforced elsewhere. - pub(crate) fn split_le_virtual(&mut self, integer: Target, num_bits: usize) -> Vec { - let bit_targets = self.add_virtual_targets(num_bits); - self.add_generator(SplitGenerator { - integer, - bits: bit_targets.clone(), - }); - bit_targets - } - /// Split the given integer into a list of wires, where each one represents a /// bit of the integer, with little-endian ordering. /// Verifies that the decomposition is correct by using `k` `BaseSum<2>` gates @@ -72,33 +56,6 @@ impl, const D: usize> CircuitBuilder { } } -/// Generator for a little-endian split. -#[must_use] -pub fn split_le_generator( - integer: Target, - bits: Vec, -) -> Box> { - Box::new(SplitGenerator { integer, bits }) -} - -/// Generator for a little-endian split. -#[must_use] -pub fn split_le_generator_local_wires( - gate: usize, - integer_input_index: usize, - bit_input_indices: &[usize], -) -> Box> { - let integer = Target::Wire(Wire { - gate, - input: integer_input_index, - }); - let bits = bit_input_indices - .iter() - .map(|&input| Target::Wire(Wire { gate, input })) - .collect(); - Box::new(SplitGenerator { integer, bits }) -} - #[derive(Debug)] struct SplitGenerator { integer: Target, diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 5b4075bd..ac3a467a 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -322,14 +322,14 @@ mod tests { let num_power_bits = power_bits.len(); - let power_bits_F: Vec<_> = power_bits + let power_bits_f: Vec<_> = power_bits .iter() .map(|b| F::from_canonical_u64(*b)) .collect(); let mut v = Vec::new(); v.push(base); - v.extend(power_bits_F.clone()); + v.extend(power_bits_f.clone()); let mut intermediate_values = Vec::new(); let mut current_intermediate_value = F::ONE; diff --git a/src/hash/merkle_tree.rs b/src/hash/merkle_tree.rs index 334e65bf..c96a0c23 100644 --- a/src/hash/merkle_tree.rs +++ b/src/hash/merkle_tree.rs @@ -13,6 +13,12 @@ use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; #[serde(bound = "")] pub struct MerkleCap(pub Vec>); +impl MerkleCap { + pub fn flatten(&self) -> Vec { + self.0.iter().flat_map(|h| h.elements).collect() + } +} + #[derive(Clone, Debug)] pub struct MerkleTree { /// The data in the leaves of the Merkle tree. diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index d783d890..1db21fa5 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -602,11 +602,7 @@ impl, const D: usize> CircuitBuilder { // TODO: This should also include an encoding of gate constraints. let circuit_digest_parts = [ - constants_sigmas_cap - .0 - .into_iter() - .flat_map(|h| h.elements) - .collect::>(), + constants_sigmas_cap.flatten(), vec![/* Add other circuit data here */], ]; let circuit_digest = hash_n_to_hash(circuit_digest_parts.concat(), false); From 8effaf76e9e6fe1e3e77a34367d2775c9171d729 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sat, 14 Aug 2021 08:48:02 -0700 Subject: [PATCH 7/9] eval_fns for PublicInputGate (#177) And a small fix in eval_fns --- src/gates/gate_testing.rs | 4 +--- src/gates/noop.rs | 1 - src/gates/public_input.rs | 7 ++++++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gates/gate_testing.rs b/src/gates/gate_testing.rs index 66bed775..4d336454 100644 --- a/src/gates/gate_testing.rs +++ b/src/gates/gate_testing.rs @@ -137,9 +137,7 @@ pub(crate) fn test_eval_fns, G: Gate, const D: usize>( let vars = EvaluationVars { local_constants: &constants, local_wires: &wires, - public_inputs_hash: &HashOut { - elements: [F::ZERO; 4], - }, + public_inputs_hash: &public_inputs_hash, }; let evals = gate.eval_unfiltered(vars); diff --git a/src/gates/noop.rs b/src/gates/noop.rs index d9a3953e..69c5c1f9 100644 --- a/src/gates/noop.rs +++ b/src/gates/noop.rs @@ -56,7 +56,6 @@ impl, const D: usize> Gate for NoopGate { #[cfg(test)] mod tests { - use crate::field::crandall_field::CrandallField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::noop::NoopGate; diff --git a/src/gates/public_input.rs b/src/gates/public_input.rs index 3d3626e6..a3f05738 100644 --- a/src/gates/public_input.rs +++ b/src/gates/public_input.rs @@ -77,11 +77,16 @@ impl, const D: usize> Gate for PublicInputGate { #[cfg(test)] mod tests { use crate::field::crandall_field::CrandallField; - use crate::gates::gate_testing::test_low_degree; + use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::public_input::PublicInputGate; #[test] fn low_degree() { test_low_degree::(PublicInputGate) } + + #[test] + fn eval_fns() -> anyhow::Result<()> { + test_eval_fns::(PublicInputGate) + } } From f3bfd666578a1de71c4bd74aa7ddf4dd6aa0ffad Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sat, 14 Aug 2021 08:53:39 -0700 Subject: [PATCH 8/9] Add a BoolTarget (#179) It's just a wrapper around `Target`, which signifies that the wrapped `Target` has already been range checked. Should make it easier to audit code that expects bools. --- src/field/field_types.rs | 4 ++++ src/fri/recursive_verifier.rs | 6 +++--- src/gadgets/arithmetic.rs | 16 ++++++++-------- src/gadgets/range_check.rs | 4 ++-- src/gadgets/select.rs | 30 +++++++++++++++++++----------- src/gadgets/split_base.rs | 20 +++++++++++--------- src/gadgets/split_join.rs | 15 ++++++++------- src/gates/exponentiation.rs | 2 +- src/hash/merkle_proofs.rs | 10 +++++----- src/iop/target.rs | 17 +++++++++++++++++ src/iop/witness.rs | 15 ++++++++++++++- src/plonk/circuit_builder.rs | 23 ++++++++++++++++++++++- 12 files changed, 114 insertions(+), 48 deletions(-) diff --git a/src/field/field_types.rs b/src/field/field_types.rs index fd5f8ac1..8d2f8872 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -185,6 +185,10 @@ pub trait Field: Self::from_canonical_u64(n as u64) } + fn from_bool(b: bool) -> Self { + Self::from_canonical_u64(b as u64) + } + fn to_canonical_biguint(&self) -> BigUint; fn from_canonical_biguint(n: BigUint) -> Self; diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index a8bd5d94..bf07639f 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -5,7 +5,7 @@ use crate::fri::proof::{FriInitialTreeProofTarget, FriProofTarget, FriQueryRound use crate::fri::FriConfig; use crate::hash::hash_types::MerkleCapTarget; use crate::iop::challenger::RecursiveChallenger; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::plonk_common::PlonkPolynomials; @@ -20,7 +20,7 @@ impl, const D: usize> CircuitBuilder { fn compute_evaluation( &mut self, x: Target, - x_index_within_coset_bits: &[Target], + x_index_within_coset_bits: &[BoolTarget], arity_bits: usize, evals: &[ExtensionTarget], beta: ExtensionTarget, @@ -181,7 +181,7 @@ impl, const D: usize> CircuitBuilder { fn fri_verify_initial_proof( &mut self, - x_index_bits: &[Target], + x_index_bits: &[BoolTarget], proof: &FriInitialTreeProofTarget, initial_merkle_caps: &[MerkleCapTarget], cap_index: Target, diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 27a204bc..2c41482e 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use crate::field::extension_field::Extendable; use crate::gates::exponentiation::ExponentiationGate; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; impl, const D: usize> CircuitBuilder { @@ -115,21 +115,21 @@ impl, const D: usize> CircuitBuilder { pub fn exp_from_bits( &mut self, base: Target, - exponent_bits: impl IntoIterator>, + exponent_bits: impl IntoIterator>, ) -> Target { - let zero = self.zero(); + let _false = self._false(); let gate = ExponentiationGate::new(self.config.clone()); let num_power_bits = gate.num_power_bits; - let mut exp_bits_vec: Vec = + let mut exp_bits_vec: Vec = exponent_bits.into_iter().map(|b| *b.borrow()).collect(); while exp_bits_vec.len() < num_power_bits { - exp_bits_vec.push(zero); + exp_bits_vec.push(_false); } let gate_index = self.add_gate(gate.clone(), vec![]); self.route(base, Target::wire(gate_index, gate.wire_base())); exp_bits_vec.iter().enumerate().for_each(|(i, bit)| { - self.route(*bit, Target::wire(gate_index, gate.wire_power_bit(i))); + self.route(bit.target, Target::wire(gate_index, gate.wire_power_bit(i))); }); Target::wire(gate_index, gate.wire_output()) @@ -148,8 +148,8 @@ impl, const D: usize> CircuitBuilder { pub fn exp_u64(&mut self, base: Target, mut exponent: u64) -> Target { let mut exp_bits = Vec::new(); while exponent != 0 { - let bit = exponent & 1; - let bit_target = self.constant(F::from_canonical_u64(bit)); + let bit = (exponent & 1) == 1; + let bit_target = self.constant_bool(bit); exp_bits.push(bit_target); exponent >>= 1; } diff --git a/src/gadgets/range_check.rs b/src/gadgets/range_check.rs index 53bbf55c..be7eaf2e 100644 --- a/src/gadgets/range_check.rs +++ b/src/gadgets/range_check.rs @@ -2,7 +2,7 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::gates::base_sum::BaseSumGate; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; @@ -15,7 +15,7 @@ impl, const D: usize> CircuitBuilder { } /// Returns the first `num_low_bits` little-endian bits of `x`. - pub fn low_bits(&mut self, x: Target, num_low_bits: usize, num_bits: usize) -> Vec { + pub fn low_bits(&mut self, x: Target, num_low_bits: usize, num_bits: usize) -> Vec { let mut res = self.split_le(x, num_bits); res.truncate(num_low_bits); res diff --git a/src/gadgets/select.rs b/src/gadgets/select.rs index 58de09c6..c81dd37b 100644 --- a/src/gadgets/select.rs +++ b/src/gadgets/select.rs @@ -1,14 +1,25 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::gates::arithmetic::ArithmeticExtensionGate; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; impl, const D: usize> CircuitBuilder { - /// Selects `x` or `y` based on `b`, which is assumed to be binary, i.e., this returns `if b { x } else { y }`. - /// This expression is gotten as `bx - (by-y)`, which can be computed with a single `ArithmeticExtensionGate`. - /// Note: This does not range-check `b`. + /// Selects `x` or `y` based on `b`, i.e., this returns `if b { x } else { y }`. pub fn select_ext( + &mut self, + b: BoolTarget, + x: ExtensionTarget, + y: ExtensionTarget, + ) -> ExtensionTarget { + let b_ext = self.convert_to_ext(b.target); + self.select_ext_generalized(b_ext, x, y) + } + + /// Like `select_ext`, but accepts a condition input which does not necessarily have to be + /// binary. In this case, it computes the arithmetic generalization of `if b { x } else { y }`, + /// i.e. `bx - (by-y)`, which can be computed with a single `ArithmeticExtensionGate`. + pub fn select_ext_generalized( &mut self, b: ExtensionTarget, x: ExtensionTarget, @@ -23,11 +34,10 @@ impl, const D: usize> CircuitBuilder { } /// See `select_ext`. - pub fn select(&mut self, b: Target, x: Target, y: Target) -> Target { - let b_ext = self.convert_to_ext(b); + pub fn select(&mut self, b: BoolTarget, x: Target, y: Target) -> Target { let x_ext = self.convert_to_ext(x); let y_ext = self.convert_to_ext(y); - self.select_ext(b_ext, x_ext, y_ext).to_target_array()[0] + self.select_ext(b, x_ext, y_ext).to_target_array()[0] } } @@ -54,13 +64,11 @@ mod tests { let (x, y) = (FF::rand(), FF::rand()); let xt = builder.add_virtual_extension_target(); let yt = builder.add_virtual_extension_target(); - let truet = builder.add_virtual_extension_target(); - let falset = builder.add_virtual_extension_target(); + let truet = builder._true(); + let falset = builder._false(); pw.set_extension_target(xt, x); pw.set_extension_target(yt, y); - pw.set_extension_target(truet, FF::ONE); - pw.set_extension_target(falset, FF::ZERO); let should_be_x = builder.select_ext(truet, xt, yt); let should_be_y = builder.select_ext(falset, xt, yt); diff --git a/src/gadgets/split_base.rs b/src/gadgets/split_base.rs index 9b481e78..69cfa377 100644 --- a/src/gadgets/split_base.rs +++ b/src/gadgets/split_base.rs @@ -4,7 +4,7 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::gates::base_sum::BaseSumGate; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; @@ -33,7 +33,7 @@ impl, const D: usize> CircuitBuilder { /// the number with little-endian bit representation given by `bits`. pub(crate) fn le_sum( &mut self, - bits: impl ExactSizeIterator> + Clone, + bits: impl ExactSizeIterator> + Clone, ) -> Target { let num_bits = bits.len(); debug_assert!( @@ -45,7 +45,7 @@ impl, const D: usize> CircuitBuilder { .clone() .zip(BaseSumGate::<2>::START_LIMBS..BaseSumGate::<2>::START_LIMBS + num_bits) { - self.route(*limb.borrow(), Target::wire(gate_index, wire)); + self.route(limb.borrow().target, Target::wire(gate_index, wire)); } self.add_generator(BaseSumGenerator::<2> { @@ -60,21 +60,23 @@ impl, const D: usize> CircuitBuilder { #[derive(Debug)] struct BaseSumGenerator { gate_index: usize, - limbs: Vec, + limbs: Vec, } impl SimpleGenerator for BaseSumGenerator { fn dependencies(&self) -> Vec { - self.limbs.clone() + self.limbs.iter().map(|b| b.target).collect() } fn run_once(&self, witness: &PartialWitness, out_buffer: &mut GeneratedValues) { let sum = self .limbs .iter() - .map(|&t| witness.get_target(t)) + .map(|&t| witness.get_bool_target(t)) .rev() - .fold(F::ZERO, |acc, limb| acc * F::from_canonical_usize(B) + limb); + .fold(F::ZERO, |acc, limb| { + acc * F::from_canonical_usize(B) + F::from_bool(limb) + }); out_buffer.set_target( Target::wire(self.gate_index, BaseSumGate::::WIRE_SUM), @@ -131,8 +133,8 @@ mod tests { let n = thread_rng().gen_range(0..(1 << 10)); let x = builder.constant(F::from_canonical_usize(n)); - let zero = builder.zero(); - let one = builder.one(); + let zero = builder._false(); + let one = builder._true(); let y = builder.le_sum( (0..10) diff --git a/src/gadgets/split_join.rs b/src/gadgets/split_join.rs index 1fe25dbe..71c171f0 100644 --- a/src/gadgets/split_join.rs +++ b/src/gadgets/split_join.rs @@ -2,7 +2,7 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::gates::base_sum::BaseSumGate; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::util::ceil_div_usize; @@ -11,8 +11,8 @@ impl, const D: usize> CircuitBuilder { /// Split the given integer into a list of wires, where each one represents a /// bit of the integer, with little-endian ordering. /// Verifies that the decomposition is correct by using `k` `BaseSum<2>` gates - /// with `k` such that `k*num_routed_wires>=num_bits`. - pub(crate) fn split_le(&mut self, integer: Target, num_bits: usize) -> Vec { + /// with `k` such that `k * num_routed_wires >= num_bits`. + pub(crate) fn split_le(&mut self, integer: Target, num_bits: usize) -> Vec { if num_bits == 0 { return Vec::new(); } @@ -24,10 +24,11 @@ impl, const D: usize> CircuitBuilder { let mut bits = Vec::with_capacity(num_bits); for &gate in &gates { - bits.extend(Target::wires_from_range( - gate, - BaseSumGate::<2>::START_LIMBS..BaseSumGate::<2>::START_LIMBS + bits_per_gate, - )); + let start_limbs = BaseSumGate::<2>::START_LIMBS; + for limb_input in start_limbs..start_limbs + bits_per_gate { + // `new_unsafe` is safe here because BaseSumGate::<2> forces it to be in `{0, 1}`. + bits.push(BoolTarget::new_unsafe(Target::wire(gate, limb_input))); + } } bits.drain(num_bits..); diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index ac3a467a..468f58e2 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -158,7 +158,7 @@ impl, const D: usize> Gate for ExponentiationGate { // power_bits is in LE order, but we accumulate in BE order. let cur_bit = power_bits[self.num_power_bits - i - 1]; - let mul_by = builder.select_ext(cur_bit, base, one); + let mul_by = builder.select_ext_generalized(cur_bit, base, one); let intermediate_value_diff = builder.mul_sub_extension(prev_intermediate_value, mul_by, intermediate_values[i]); constraints.push(intermediate_value_diff); diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index 45009c7d..1b42e393 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -10,7 +10,7 @@ use crate::gates::gmimc::GMiMCGate; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; use crate::hash::hashing::{compress, hash_or_noop, GMIMC_ROUNDS}; use crate::hash::merkle_tree::MerkleCap; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::wire::Wire; use crate::plonk::circuit_builder::CircuitBuilder; @@ -66,7 +66,7 @@ impl, const D: usize> CircuitBuilder { pub(crate) fn verify_merkle_proof( &mut self, leaf_data: Vec, - leaf_index_bits: &[Target], + leaf_index_bits: &[BoolTarget], merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, ) { @@ -83,7 +83,7 @@ impl, const D: usize> CircuitBuilder { gate, input: swap_wire, }); - self.generate_copy(bit, swap_wire); + self.generate_copy(bit.target, swap_wire); let input_wires = (0..12) .map(|i| { @@ -131,7 +131,7 @@ impl, const D: usize> CircuitBuilder { pub(crate) fn verify_merkle_proof_with_cap_index( &mut self, leaf_data: Vec, - leaf_index_bits: &[Target], + leaf_index_bits: &[BoolTarget], cap_index: Target, merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, @@ -149,7 +149,7 @@ impl, const D: usize> CircuitBuilder { gate, input: swap_wire, }); - self.generate_copy(bit, swap_wire); + self.generate_copy(bit.target, swap_wire); let input_wires = (0..12) .map(|i| { diff --git a/src/iop/target.rs b/src/iop/target.rs index 50bd6bb6..877da5b8 100644 --- a/src/iop/target.rs +++ b/src/iop/target.rs @@ -31,3 +31,20 @@ impl Target { range.map(|i| Self::wire(gate, i)).collect() } } + +/// A `Target` which has already been constrained such that it can only be 0 or 1. +#[derive(Copy, Clone, Debug)] +pub struct BoolTarget { + pub target: Target, + /// This private field is here to force all instantiations to go through `new_unsafe`. + _private: (), +} + +impl BoolTarget { + pub fn new_unsafe(target: Target) -> BoolTarget { + BoolTarget { + target, + _private: (), + } + } +} diff --git a/src/iop/witness.rs b/src/iop/witness.rs index f2c0d453..51b5a182 100644 --- a/src/iop/witness.rs +++ b/src/iop/witness.rs @@ -9,7 +9,7 @@ use crate::gates::gate::GateInstance; use crate::hash::hash_types::HashOutTarget; use crate::hash::hash_types::{HashOut, MerkleCapTarget}; use crate::hash::merkle_tree::MerkleCap; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::wire::Wire; use crate::plonk::copy_constraint::CopyConstraint; @@ -70,6 +70,15 @@ impl PartialWitness { .collect() } + pub fn get_bool_target(&self, target: BoolTarget) -> bool { + let value = self.get_target(target.target).to_canonical_u64(); + match value { + 0 => false, + 1 => true, + _ => panic!("not a bool"), + } + } + pub fn get_hash_target(&self, ht: HashOutTarget) -> HashOut { HashOut { elements: self.get_targets(&ht.elements).try_into().unwrap(), @@ -180,6 +189,10 @@ impl PartialWitness { .for_each(|(&et, &v)| self.set_extension_target(et, v)); } + pub fn set_bool_target(&mut self, target: BoolTarget, value: bool) { + self.set_target(target.target, F::from_bool(value)) + } + pub fn set_wire(&mut self, wire: Wire, value: F) { self.set_target(Target::Wire(wire), value) } diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index 1db21fa5..aa8998b6 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -16,7 +16,7 @@ use crate::gates::public_input::PublicInputGate; use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget}; use crate::hash::hashing::hash_n_to_hash; use crate::iop::generator::{CopyGenerator, RandomValueGenerator, WitnessGenerator}; -use crate::iop::target::Target; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::wire::Wire; use crate::plonk::circuit_data::{ CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData, @@ -129,6 +129,11 @@ impl, const D: usize> CircuitBuilder { .collect() } + // TODO: Unsafe + pub fn add_virtual_bool_target(&mut self) -> BoolTarget { + BoolTarget::new_unsafe(self.add_virtual_target()) + } + /// Adds a gate to the circuit, and returns its index. pub fn add_gate>(&mut self, gate_type: G, constants: Vec) -> usize { self.check_gate_compatibility(&gate_type); @@ -279,6 +284,14 @@ impl, const D: usize> CircuitBuilder { self.constant(F::NEG_ONE) } + pub fn _false(&mut self) -> BoolTarget { + BoolTarget::new_unsafe(self.zero()) + } + + pub fn _true(&mut self) -> BoolTarget { + BoolTarget::new_unsafe(self.one()) + } + /// Returns a routable target with the given constant value. pub fn constant(&mut self, c: F) -> Target { if let Some(&target) = self.constants_to_targets.get(&c) { @@ -300,6 +313,14 @@ impl, const D: usize> CircuitBuilder { constants.iter().map(|&c| self.constant(c)).collect() } + pub fn constant_bool(&mut self, b: bool) -> BoolTarget { + if b { + self._true() + } else { + self._false() + } + } + /// If the given target is a constant (i.e. it was created by the `constant(F)` method), returns /// its constant value. Otherwise, returns `None`. pub fn target_as_constant(&self, target: Target) -> Option { From e4cbee2b5778b0c49e22c582947dbd2b0a8498ac Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sat, 14 Aug 2021 10:01:10 -0700 Subject: [PATCH 9/9] Disable ZK in `large_config` (#180) * Disable ZK in large_config Speeds up the tests from ~6m to ~1m (debug mode). `large_config` is crate-private so I don't think we need to worry about real users forgetting ZK, and I don't think ZK seems important in these tests, though we should probably have ZK enabled for a couple tests. A couple tests need ZK or they fail; I added a TODO to look later. This led to a few other changes: - Fixed a bug where `trim` could truncate the final poly to a non-power-of-two length. This was improbable when ZK is on due to randomization. - Gave a few methods access to the whole `CircuitConfig` vs `FriConfig` -- sort of necessary for the above fix, and I don't think there's much downside. - Remove `cap_height` from `FriConfig` -- didn't really need it any more after giving more methods access to `CircuitConfig`, and having a single copy of the param feels cleaner/safer to me. * PR feedback --- src/bin/bench_recursion.rs | 1 - src/fri/commitment.rs | 23 ++++++++++++++--------- src/fri/mod.rs | 2 -- src/fri/prover.rs | 24 ++++++++++++++++-------- src/fri/recursive_verifier.rs | 10 ++++------ src/gadgets/arithmetic_extension.rs | 2 +- src/gadgets/interpolation.rs | 2 +- src/plonk/circuit_data.rs | 16 +++++++++++++--- src/plonk/recursive_verifier.rs | 2 -- src/util/mod.rs | 2 +- 10 files changed, 50 insertions(+), 34 deletions(-) diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index 7067bd49..d3e4e1e0 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -32,7 +32,6 @@ fn bench_prove, const D: usize>() -> Result<()> { proof_of_work_bits: 20, reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], num_query_rounds: 35, - cap_height: 1, }, }; diff --git a/src/fri/commitment.rs b/src/fri/commitment.rs index d62fa33d..7e7dab6e 100644 --- a/src/fri/commitment.rs +++ b/src/fri/commitment.rs @@ -205,7 +205,7 @@ impl PolynomialBatchCommitment { lde_final_poly, lde_final_values, challenger, - &config.fri_config, + &config, timing, ); @@ -281,8 +281,8 @@ mod tests { proof_of_work_bits: 2, reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, - cap_height: 1, }; + // We only care about `fri_config, num_constants`, and `num_routed_wires` here. let common_data = CommonCircuitData { config: CircuitConfig { @@ -300,12 +300,12 @@ mod tests { circuit_digest: HashOut::from_partial(vec![]), }; - let lpcs = (0..4) + let commitments = (0..4) .map(|i| { PolynomialBatchCommitment::::from_values( gen_random_test_case(ks[i], degree_bits), common_data.config.rate_bits, - PlonkPolynomials::polynomials(i).blinding, + common_data.config.zero_knowledge && PlonkPolynomials::polynomials(i).blinding, common_data.config.cap_height, &mut TimingTree::default(), ) @@ -314,7 +314,12 @@ mod tests { let zeta = gen_random_point::(degree_bits); let (proof, os) = PolynomialBatchCommitment::open_plonk::( - &[&lpcs[0], &lpcs[1], &lpcs[2], &lpcs[3]], + &[ + &commitments[0], + &commitments[1], + &commitments[2], + &commitments[3], + ], zeta, &mut Challenger::new(), &common_data, @@ -322,10 +327,10 @@ mod tests { ); let merkle_caps = &[ - lpcs[0].merkle_tree.cap.clone(), - lpcs[1].merkle_tree.cap.clone(), - lpcs[2].merkle_tree.cap.clone(), - lpcs[3].merkle_tree.cap.clone(), + commitments[0].merkle_tree.cap.clone(), + commitments[1].merkle_tree.cap.clone(), + commitments[2].merkle_tree.cap.clone(), + commitments[3].merkle_tree.cap.clone(), ]; verify_fri_proof( diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 55a41abd..716260a3 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -16,6 +16,4 @@ pub struct FriConfig { /// Number of query rounds to perform. pub num_query_rounds: usize, - - pub cap_height: usize, } diff --git a/src/fri/prover.rs b/src/fri/prover.rs index 52db4579..c1f53a1c 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -8,6 +8,7 @@ use crate::hash::hash_types::HashOut; use crate::hash::hashing::hash_n_to_1; use crate::hash::merkle_tree::MerkleTree; use crate::iop::challenger::Challenger; +use crate::plonk::circuit_data::CircuitConfig; use crate::plonk::plonk_common::reduce_with_powers; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::timed; @@ -22,7 +23,7 @@ pub fn fri_proof, const D: usize>( // Evaluation of the polynomial on the large domain. lde_polynomial_values: PolynomialValues, challenger: &mut Challenger, - config: &FriConfig, + config: &CircuitConfig, timing: &mut TimingTree, ) -> FriProof { let n = lde_polynomial_values.values.len(); @@ -45,12 +46,17 @@ pub fn fri_proof, const D: usize>( let pow_witness = timed!( timing, "find for proof-of-work witness", - fri_proof_of_work(current_hash, config) + fri_proof_of_work(current_hash, &config.fri_config) ); // Query phase - let query_round_proofs = - fri_prover_query_rounds(initial_merkle_trees, &trees, challenger, n, config); + let query_round_proofs = fri_prover_query_rounds( + initial_merkle_trees, + &trees, + challenger, + n, + &config.fri_config, + ); FriProof { commit_phase_merkle_caps: trees.iter().map(|t| t.cap.clone()).collect(), @@ -64,14 +70,14 @@ fn fri_committed_trees, const D: usize>( mut coeffs: PolynomialCoeffs, mut values: PolynomialValues, challenger: &mut Challenger, - config: &FriConfig, + config: &CircuitConfig, ) -> (Vec>, PolynomialCoeffs) { let mut trees = Vec::new(); let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR; - let num_reductions = config.reduction_arity_bits.len(); + let num_reductions = config.fri_config.reduction_arity_bits.len(); for i in 0..num_reductions { - let arity = 1 << config.reduction_arity_bits[i]; + let arity = 1 << config.fri_config.reduction_arity_bits[i]; reverse_index_bits_in_place(&mut values.values); let chunked_values = values @@ -97,7 +103,9 @@ fn fri_committed_trees, const D: usize>( values = coeffs.coset_fft(shift.into()) } - coeffs.trim(); + /// The coefficients being removed here should always be zero. + coeffs.coeffs.truncate(coeffs.len() >> config.rate_bits); + challenger.observe_extension_elements(&coeffs.coeffs); (trees, coeffs) } diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index bf07639f..c9f15aec 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -291,15 +291,13 @@ impl, const D: usize> CircuitBuilder { round_proof: &FriQueryRoundTarget, common_data: &CommonCircuitData, ) { - let config = &common_data.config.fri_config; + let config = &common_data.config; let n_log = log2_strict(n); // 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.fri_config.cap_height..] - .into_iter(), - ); + let cap_index = self + .le_sum(x_index_bits[x_index_bits.len() - common_data.config.cap_height..].into_iter()); with_context!( self, "check FRI initial proof", @@ -349,7 +347,7 @@ impl, const D: usize> CircuitBuilder { ) ); - for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() { + for (i, &arity_bits) in config.fri_config.reduction_arity_bits.iter().enumerate() { let evals = &round_proof.steps[i].evals; // Split x_index into the index of the coset x is in, and the index of x within that coset. diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 8b7c11e3..7ab8d359 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -712,7 +712,7 @@ mod tests { type FF = QuarticCrandallField; const D: usize = 4; - let config = CircuitConfig::large_config(); + let config = CircuitConfig::large_zk_config(); let pw = PartialWitness::new(config.num_wires); let mut builder = CircuitBuilder::::new(config); diff --git a/src/gadgets/interpolation.rs b/src/gadgets/interpolation.rs index 92090d90..9d48a204 100644 --- a/src/gadgets/interpolation.rs +++ b/src/gadgets/interpolation.rs @@ -113,7 +113,7 @@ mod tests { fn test_interpolate2() -> Result<()> { type F = CrandallField; type FF = QuarticCrandallField; - let config = CircuitConfig::large_config(); + let config = CircuitConfig::large_zk_config(); let pw = PartialWitness::new(config.num_wires); let mut builder = CircuitBuilder::::new(config); diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index 2441d810..3b9becab 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -48,7 +48,6 @@ impl Default for CircuitConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, - cap_height: 1, }, } } @@ -66,14 +65,25 @@ impl CircuitConfig { security_bits: 128, rate_bits: 3, num_challenges: 3, - zero_knowledge: true, + zero_knowledge: false, cap_height: 1, + fri_config: FriConfig { + proof_of_work_bits: 1, + reduction_arity_bits: vec![1], + num_query_rounds: 1, + }, + } + } + + pub(crate) fn large_zk_config() -> Self { + CircuitConfig { + zero_knowledge: true, fri_config: FriConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, - cap_height: 1, }, + ..Self::large_config() } } } diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index ea35d505..27e8f2fb 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -375,7 +375,6 @@ mod tests { proof_of_work_bits: 1, reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], num_query_rounds: 40, - cap_height: 1, }, }; let (proof_with_pis, vd, cd) = { @@ -431,7 +430,6 @@ mod tests { proof_of_work_bits: 1, reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], num_query_rounds: 40, - cap_height: 3, }, }; let (proof_with_pis, vd, cd) = { diff --git a/src/util/mod.rs b/src/util/mod.rs index 7ee995f5..b468ab35 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -26,7 +26,7 @@ pub(crate) fn log2_ceil(n: usize) -> usize { /// Computes `log_2(n)`, panicking if `n` is not a power of two. pub(crate) fn log2_strict(n: usize) -> usize { - assert!(n.is_power_of_two(), "Not a power of two"); + assert!(n.is_power_of_two(), "Not a power of two: {}", n); log2_ceil(n) }