From 5c2c01b1abe33ff4e11db60e576a05f624532ed3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 13 Jul 2021 15:20:14 +0200 Subject: [PATCH] Circuit compiles --- src/field/extension_field/target.rs | 2 +- src/fri/recursive_verifier.rs | 80 ++++++++++-------------- src/merkle_proofs.rs | 94 ++++++++++++++++++++++++++++- src/prover.rs | 6 +- src/recursive_verifier.rs | 8 ++- src/verifier.rs | 1 - 6 files changed, 132 insertions(+), 59 deletions(-) diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 9d60847e..455ee38f 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -32,7 +32,7 @@ impl ExtensionTarget { } let arr = self.to_target_array(); let k = (F::ORDER - 1) / (D as u64); - let z0 = F::W.exp(k * count as u64); + let z0 = F::Extension::W.exp(k * count as u64); let zs = z0 .powers() .take(D) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index fad2317c..f76a7506 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -1,3 +1,4 @@ +use env_logger::builder; use itertools::izip; use crate::circuit_builder::CircuitBuilder; @@ -12,6 +13,7 @@ use crate::proof::{ FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, HashTarget, OpeningSetTarget, }; use crate::target::Target; +use crate::util::scaling::ReducingFactorTarget; use crate::util::{log2_strict, reverse_index_bits_in_place}; impl, const D: usize> CircuitBuilder { @@ -123,7 +125,7 @@ impl, const D: usize> CircuitBuilder { n, &betas, round_proof, - config, + common_data, ); } } @@ -146,12 +148,13 @@ impl, const D: usize> CircuitBuilder { os: &OpeningSetTarget, zeta: ExtensionTarget, subgroup_x: Target, + common_data: &CommonCircuitData, ) -> ExtensionTarget { assert!(D > 1, "Not implemented for D=1."); let config = &self.config.fri_config.clone(); let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; let subgroup_x = self.convert_to_ext(subgroup_x); - let mut alpha_powers = self.powers(alpha); + let mut alpha = ReducingFactorTarget::new(alpha); let mut sum = self.zero_extension(); // We will add three terms to `sum`: @@ -166,50 +169,42 @@ impl, const D: usize> CircuitBuilder { ] .iter() .flat_map(|&p| proof.unsalted_evals(p)) + .chain( + &proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS) + [common_data.partial_products_range()], + ) .map(|&e| self.convert_to_ext(e)) .collect::>(); let single_openings = os .constants .iter() .chain(&os.plonk_sigmas) - .chain(&os.quotient_polys); - let mut single_numerator = self.zero_extension(); - for (e, &o) in izip!(single_evals, single_openings) { - let a = alpha_powers.next(self); - let diff = self.sub_extension(e, o); - single_numerator = self.mul_add_extension(a, diff, single_numerator); - } + .chain(&os.quotient_polys) + .chain(&os.partial_products) + .copied() + .collect::>(); + let mut single_numerator = alpha.reduce(&single_evals, self); + // TODO: Precompute the rhs as it is the same in all FRI round. + let rhs = alpha.reduce(&single_openings, self); + single_numerator = self.sub_extension(single_numerator, rhs); let single_denominator = self.sub_extension(subgroup_x, zeta); let quotient = self.div_unsafe_extension(single_numerator, single_denominator); sum = self.add_extension(sum, quotient); + alpha.reset(); // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof .unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS) .iter() + .take(common_data.zs_range().end) .map(|&e| self.convert_to_ext(e)) .collect::>(); - // TODO: Would probably be more efficient using `CircuitBuilder::reduce_with_powers_recursive` - let mut zs_composition_eval = self.zero_extension(); - let mut alpha_powers_cloned = alpha_powers.clone(); - for &e in &zs_evals { - let a = alpha_powers_cloned.next(self); - zs_composition_eval = self.mul_add_extension(a, e, zs_composition_eval); - } + let mut zs_composition_eval = alpha.clone().reduce(&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 mut zs_ev_zeta = self.zero_extension(); - let mut alpha_powers_cloned = alpha_powers.clone(); - for &t in &os.plonk_zs { - let a = alpha_powers_cloned.next(self); - zs_ev_zeta = self.mul_add_extension(a, t, zs_ev_zeta); - } - let mut zs_ev_zeta_right = self.zero_extension(); - for &t in &os.plonk_zs_right { - let a = alpha_powers.next(self); - zs_ev_zeta_right = self.mul_add_extension(a, t, zs_ev_zeta); - } + let zs_ev_zeta = alpha.clone().reduce(&os.plonk_zs, self); + let zs_ev_zeta_right = alpha.reduce(&os.plonk_zs_right, self); let interpol_val = self.interpolate2( [(zeta, zs_ev_zeta), (zeta_right, zs_ev_zeta_right)], subgroup_x, @@ -219,6 +214,7 @@ impl, const D: usize> CircuitBuilder { let vanish_zeta_right = self.sub_extension(subgroup_x, zeta_right); let zs_denominator = self.mul_extension(vanish_zeta, vanish_zeta_right); let zs_quotient = self.div_unsafe_extension(zs_numerator, zs_denominator); + sum = alpha.shift(sum, self); sum = self.add_extension(sum, zs_quotient); // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. @@ -227,26 +223,11 @@ impl, const D: usize> CircuitBuilder { .iter() .map(|&e| self.convert_to_ext(e)) .collect::>(); - let mut wire_composition_eval = self.zero_extension(); - let mut alpha_powers_cloned = alpha_powers.clone(); - for &e in &wire_evals { - let a = alpha_powers_cloned.next(self); - wire_composition_eval = self.mul_add_extension(a, e, wire_composition_eval); - } - let mut alpha_powers_cloned = alpha_powers.clone(); - let wire_eval = os.wires.iter().fold(self.zero_extension(), |acc, &w| { - let a = alpha_powers_cloned.next(self); - self.mul_add_extension(a, w, acc) - }); - let mut alpha_powers_frob = alpha_powers.repeated_frobenius(D - 1, self); - let wire_eval_frob = os - .wires - .iter() - .fold(self.zero_extension(), |acc, &w| { - let a = alpha_powers_frob.next(self); - self.mul_add_extension(a, w, acc) - }) - .frobenius(self); + let mut wire_composition_eval = alpha.clone().reduce(&wire_evals, self); + let mut alpha_frob = alpha.repeated_frobenius(D - 1, self); + let wire_eval = alpha.reduce(&os.wires, self); + let wire_eval_frob = alpha_frob.reduce(&os.wires, self); + let wire_eval_frob = wire_eval_frob.frobenius(self); let zeta_frob = zeta.frobenius(self); let wire_interpol_val = self.interpolate2([(zeta, wire_eval), (zeta_frob, wire_eval_frob)], subgroup_x); @@ -254,6 +235,7 @@ impl, const D: usize> CircuitBuilder { let vanish_zeta_frob = self.sub_extension(subgroup_x, zeta_frob); let wire_denominator = self.mul_extension(vanish_zeta, vanish_zeta_frob); let wire_quotient = self.div_unsafe_extension(wire_numerator, wire_denominator); + sum = alpha.shift(sum, self); sum = self.add_extension(sum, wire_quotient); sum @@ -270,8 +252,9 @@ impl, const D: usize> CircuitBuilder { n: usize, betas: &[ExtensionTarget], round_proof: &FriQueryRoundTarget, - config: &FriConfig, + common_data: &CommonCircuitData, ) { + let config = &common_data.config.fri_config; let n_log = log2_strict(n); let mut evaluations: Vec>> = Vec::new(); // TODO: Do we need to range check `x_index` to a target smaller than `p`? @@ -302,6 +285,7 @@ impl, const D: usize> CircuitBuilder { os, zeta, subgroup_x, + common_data, ) } else { let last_evals = &evaluations[i - 1]; diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index 002a0d5a..fee57d19 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -8,6 +8,7 @@ use crate::hash::GMIMC_ROUNDS; use crate::hash::{compress, hash_or_noop}; use crate::proof::{Hash, HashTarget}; use crate::target::Target; +use crate::util::marking::MarkedTargets; use crate::wire::Wire; #[derive(Clone, Debug)] @@ -56,6 +57,81 @@ pub(crate) fn verify_merkle_proof( } impl, const D: usize> CircuitBuilder { + pub(crate) fn verify_merkle_proof_marked( + &mut self, + leaf_data: Vec, + leaf_index: Target, + merkle_root: HashTarget, + proof: &MerkleProofTarget, + marked: &mut Vec, + ) { + let zero = self.zero(); + let height = proof.siblings.len(); + let purported_index_bits = self.split_le_virtual(leaf_index, height); + + let mut state: HashTarget = self.hash_or_noop(leaf_data); + let mut acc_leaf_index = zero; + + for (bit, &sibling) in purported_index_bits.into_iter().zip(&proof.siblings) { + let gate = self + .add_gate_no_constants(GMiMCGate::::with_automatic_constants()); + + let swap_wire = GMiMCGate::::WIRE_SWAP; + let swap_wire = Target::Wire(Wire { + gate, + input: swap_wire, + }); + self.generate_copy(bit, swap_wire); + + let old_acc_wire = GMiMCGate::::WIRE_INDEX_ACCUMULATOR_OLD; + let old_acc_wire = Target::Wire(Wire { + gate, + input: old_acc_wire, + }); + self.route(acc_leaf_index, old_acc_wire); + + let new_acc_wire = GMiMCGate::::WIRE_INDEX_ACCUMULATOR_NEW; + let new_acc_wire = Target::Wire(Wire { + gate, + input: new_acc_wire, + }); + acc_leaf_index = new_acc_wire; + + let input_wires = (0..12) + .map(|i| { + Target::Wire(Wire { + gate, + input: GMiMCGate::::wire_input(i), + }) + }) + .collect::>(); + + for i in 0..4 { + self.route(state.elements[i], input_wires[i]); + self.route(sibling.elements[i], input_wires[4 + i]); + self.route(zero, input_wires[8 + i]); + } + + state = HashTarget::from_vec( + (0..4) + .map(|i| { + Target::Wire(Wire { + gate, + input: GMiMCGate::::wire_output(i), + }) + }) + .collect(), + ) + } + + // self.assert_equal(acc_leaf_index, leaf_index); + marked.push(MarkedTargets { + targets: Box::new(acc_leaf_index), + name: "acc leaf".to_string(), + }); + + self.assert_hashes_equal(state, merkle_root) + } /// Verifies that the given leaf data is present at the given index in the Merkle tree with the /// given root. pub(crate) fn verify_merkle_proof( @@ -124,7 +200,8 @@ impl, const D: usize> CircuitBuilder { ) } - self.assert_equal(acc_leaf_index, leaf_index); + let leaf_index_rev = self.reverse_limbs::<2>(leaf_index, height); + self.assert_equal(acc_leaf_index, leaf_index_rev); self.assert_hashes_equal(state, merkle_root) } @@ -147,6 +224,7 @@ mod tests { use crate::field::extension_field::quartic::QuarticCrandallField; use crate::merkle_proofs::verify_merkle_proof; use crate::merkle_tree::MerkleTree; + use crate::util::marking::MarkedTargets; use crate::verifier::verify; use crate::witness::PartialWitness; @@ -155,12 +233,13 @@ mod tests { } #[test] - fn test_merkle_trees() -> Result<()> { + fn test_recursive_merkle_proof() -> Result<()> { type F = CrandallField; type FF = QuarticCrandallField; let config = CircuitConfig::large_config(); let mut builder = CircuitBuilder::::new(config); let mut pw = PartialWitness::new(); + let mut marked = Vec::new(); let log_n = 8; let n = 1 << log_n; @@ -186,10 +265,19 @@ mod tests { pw.set_target(data[j], tree.leaves[i][j]); } + marked.push(MarkedTargets { + targets: Box::new(i_c), + name: "i_c".to_string(), + }); + marked.push(MarkedTargets { + targets: Box::new(builder.reverse_limbs::<2>(i_c, log_n)), + name: "rev i_c".to_string(), + }); + builder.verify_merkle_proof_marked(data.clone(), i_c, root_t, &proof_t, &mut marked); builder.verify_merkle_proof(data, i_c, root_t, &proof_t); let data = builder.build(); - let proof = data.prove(pw); + let proof = data.prove_marked(pw, marked); verify(proof, &data.verifier_only, &data.common) } diff --git a/src/prover.rs b/src/prover.rs index 397b0fea..23c07514 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -46,15 +46,15 @@ pub(crate) fn prove, const D: usize>( "to compute full witness" ); + for m in marked { + m.display(&witness); + } timed!( witness .check_copy_constraints(&prover_data.copy_constraints, &prover_data.gate_instances) .unwrap(), // TODO: Change return value to `Result` and use `?` here. "to check copy constraints" ); - for m in marked { - m.display(&witness); - } let wires_values: Vec> = timed!( witness diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 7a35c728..2bc77e07 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -91,7 +91,6 @@ impl, const D: usize> CircuitBuilder { let mut scale = ReducingFactorTarget::new(zeta_pow_deg); let mut rhs = scale.reduce(chunk, self); rhs = self.mul_extension(z_h_zeta, rhs); - dbg!(self.num_gates()); self.route_extension(vanishing_polys_zeta[i], rhs); } @@ -122,6 +121,7 @@ mod tests { use super::*; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::extension_field::target::ExtensionTarget; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::merkle_proofs::MerkleProofTarget; use crate::polynomial::commitment::OpeningProofTarget; @@ -129,6 +129,7 @@ mod tests { FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, HashTarget, OpeningSetTarget, Proof, }; + use crate::target::Target; use crate::verifier::verify; use crate::witness::PartialWitness; @@ -322,9 +323,10 @@ mod tests { fn test_recursive_verifier() { type F = CrandallField; type FF = QuarticCrandallField; + const D: usize = 4; let (proof, vd, cd) = { let config = CircuitConfig::large_config(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let zero = builder.zero(); let hash = builder.hash_n_to_m(vec![zero], 2, true); let z = builder.mul(hash[0], hash[1]); @@ -338,7 +340,7 @@ mod tests { verify(proof.clone(), &vd, &cd).unwrap(); let config = CircuitConfig::large_config(); - let mut builder = CircuitBuilder::::new(config.clone()); + let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); let mut marked = Vec::new(); let pt = proof_to_proof_target(&proof, &mut builder); diff --git a/src/verifier.rs b/src/verifier.rs index 6da5a2e2..e1d6d967 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -56,7 +56,6 @@ pub(crate) fn verify, const D: usize>( &gammas, &alphas, ); - dbg!(vanishing_polys_zeta[0]); // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta. let quotient_polys_zeta = &proof.openings.quotient_polys;