From b50a9809dbc596d4c4da5a4b18d3ca078430328e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 8 Jul 2021 17:16:26 +0200 Subject: [PATCH 01/21] Start recursive verifier test --- src/circuit_builder.rs | 22 +++- src/merkle_proofs.rs | 1 + src/polynomial/commitment.rs | 4 +- src/proof.rs | 10 +- src/recursive_verifier.rs | 240 +++++++++++++++++++++++++++++++++-- src/witness.rs | 8 ++ 6 files changed, 268 insertions(+), 17 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index c9f35212..1d386b9d 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -1,4 +1,5 @@ use std::collections::{HashMap, HashSet}; +use std::convert::TryInto; use std::time::Instant; use log::info; @@ -20,6 +21,7 @@ use crate::permutation_argument::TargetPartition; use crate::plonk_common::PlonkPolynomials; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::polynomial::polynomial::PolynomialValues; +use crate::proof::HashTarget; use crate::target::Target; use crate::util::partial_products::num_partial_products; use crate::util::{log2_ceil, log2_strict, transpose, transpose_poly_values}; @@ -38,7 +40,7 @@ pub struct CircuitBuilder, const D: usize> { public_input_index: usize, /// The next available index for a `VirtualTarget`. - virtual_target_index: usize, + pub virtual_target_index: usize, copy_constraints: Vec<(Target, Target)>, @@ -92,6 +94,24 @@ impl, const D: usize> CircuitBuilder { (0..n).map(|_i| self.add_virtual_target()).collect() } + pub fn add_virtual_hash(&mut self) -> HashTarget { + HashTarget::from_vec(self.add_virtual_targets(4)) + } + + pub fn add_virtual_hashes(&mut self, n: usize) -> Vec { + (0..n).map(|_i| self.add_virtual_hash()).collect() + } + + pub fn add_virtual_extension_target(&mut self) -> ExtensionTarget { + ExtensionTarget(self.add_virtual_targets(D).try_into().unwrap()) + } + + pub fn add_virtual_extension_targets(&mut self, n: usize) -> Vec> { + (0..n) + .map(|_i| self.add_virtual_extension_target()) + .collect() + } + pub fn add_gate_no_constants(&mut self, gate_type: GateRef) -> usize { self.add_gate(gate_type, Vec::new()) } diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index 7d50f466..b098657c 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -16,6 +16,7 @@ pub struct MerkleProof { pub siblings: Vec>, } +#[derive(Clone)] pub struct MerkleProofTarget { /// The Merkle digest of each sibling subtree, staying from the bottommost layer. pub siblings: Vec, diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 7298331c..286f03c9 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -246,7 +246,7 @@ impl ListPolynomialCommitment { } pub struct OpeningProof, const D: usize> { - fri_proof: FriProof, + pub fri_proof: FriProof, // TODO: Get the degree from `CommonCircuitData` instead. quotient_degree: usize, } @@ -278,7 +278,7 @@ impl, const D: usize> OpeningProof { } pub struct OpeningProofTarget { - fri_proof: FriProofTarget, + pub fri_proof: FriProofTarget, } #[cfg(test)] diff --git a/src/proof.rs b/src/proof.rs index f712da40..2c83fb33 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -61,7 +61,7 @@ impl HashTarget { } } -pub struct Proof, const D: usize> { +pub struct Proof, const D: usize> { /// Merkle root of LDEs of wire values. pub wires_root: Hash, /// Merkle root of LDEs of Z, in the context of Plonk's permutation argument. @@ -78,8 +78,8 @@ pub struct ProofTarget { pub wires_root: HashTarget, pub plonk_zs_root: HashTarget, pub quotient_polys_root: HashTarget, - pub openings: Vec>, - pub opening_proof: Vec>, + pub openings: OpeningSetTarget, + pub opening_proof: OpeningProofTarget, } /// Evaluations and Merkle proof produced by the prover in a FRI query step. @@ -88,6 +88,7 @@ pub struct FriQueryStep, const D: usize> { pub merkle_proof: MerkleProof, } +#[derive(Clone)] pub struct FriQueryStepTarget { pub evals: Vec>, pub merkle_proof: MerkleProofTarget, @@ -106,6 +107,7 @@ impl FriInitialTreeProof { } } +#[derive(Clone)] pub struct FriInitialTreeProofTarget { pub evals_proofs: Vec<(Vec, MerkleProofTarget)>, } @@ -123,6 +125,7 @@ pub struct FriQueryRound, const D: usize> { pub steps: Vec>, } +#[derive(Clone)] pub struct FriQueryRoundTarget { pub initial_trees_proof: FriInitialTreeProofTarget, pub steps: Vec>, @@ -198,5 +201,6 @@ pub struct OpeningSetTarget { pub wires: Vec>, pub plonk_zs: Vec>, pub plonk_zs_right: Vec>, + pub partial_products: Vec>, pub quotient_polys: Vec>, } diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index bb9d724e..91ab2cd6 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -7,16 +7,234 @@ use crate::proof::ProofTarget; const MIN_WIRES: usize = 120; // TODO: Double check. const MIN_ROUTED_WIRES: usize = 28; // TODO: Double check. -/// Recursively verifies an inner proof. -pub fn add_recursive_verifier, const D: usize>( - builder: &mut CircuitBuilder, - inner_config: CircuitConfig, - inner_circuit: VerifierCircuitTarget, - inner_gates: Vec>, - inner_proof: ProofTarget, -) { - assert!(builder.config.num_wires >= MIN_WIRES); - assert!(builder.config.num_wires >= MIN_ROUTED_WIRES); +impl, const D: usize> CircuitBuilder { + /// Recursively verifies an inner proof. + pub fn add_recursive_verifier( + &mut self, + inner_config: CircuitConfig, + inner_circuit: VerifierCircuitTarget, + inner_gates: Vec>, + inner_proof: ProofTarget, + ) { + assert!(self.config.num_wires >= MIN_WIRES); + assert!(self.config.num_wires >= MIN_ROUTED_WIRES); - todo!() + todo!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; + use crate::merkle_proofs::MerkleProofTarget; + use crate::polynomial::commitment::OpeningProofTarget; + use crate::proof::{ + FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, + HashTarget, OpeningSetTarget, Proof, + }; + use crate::witness::PartialWitness; + + fn proof_to_proof_target, const D: usize>( + proof: &Proof, + builder: &mut CircuitBuilder, + ) -> ProofTarget { + let wires_root = builder.add_virtual_hash(); + let plonk_zs_root = builder.add_virtual_hash(); + let quotient_polys_root = builder.add_virtual_hash(); + + let openings = OpeningSetTarget { + constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), + plonk_sigmas: builder + .add_virtual_extension_targets(proof.openings.plonk_s_sigmas.len()), + wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), + plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), + plonk_zs_right: builder + .add_virtual_extension_targets(proof.openings.plonk_zs_right.len()), + partial_products: builder + .add_virtual_extension_targets(proof.openings.partial_products.len()), + quotient_polys: builder + .add_virtual_extension_targets(proof.openings.quotient_polys.len()), + }; + + let mut query_round = FriQueryRoundTarget { + initial_trees_proof: FriInitialTreeProofTarget { + evals_proofs: vec![], + }, + steps: vec![], + }; + for (v, merkle_proof) in &proof.opening_proof.fri_proof.query_round_proofs[0] + .initial_trees_proof + .evals_proofs + { + query_round.initial_trees_proof.evals_proofs.push(( + builder.add_virtual_targets(v.len()), + MerkleProofTarget { + siblings: builder.add_virtual_hashes(merkle_proof.siblings.len()), + }, + )); + } + for step in &proof.opening_proof.fri_proof.query_round_proofs[0].steps { + query_round.steps.push(FriQueryStepTarget { + evals: builder.add_virtual_extension_targets(step.evals.len()), + merkle_proof: MerkleProofTarget { + siblings: builder.add_virtual_hashes(step.merkle_proof.siblings.len()), + }, + }); + } + + let opening_proof = + OpeningProofTarget { + fri_proof: FriProofTarget { + commit_phase_merkle_roots: vec![ + builder.add_virtual_hash(); + proof + .opening_proof + .fri_proof + .commit_phase_merkle_roots + .len() + ], + query_round_proofs: vec![ + query_round.clone(); + proof.opening_proof.fri_proof.query_round_proofs.len() + ], + final_poly: PolynomialCoeffsExtTarget(builder.add_virtual_extension_targets( + proof.opening_proof.fri_proof.final_poly.len(), + )), + pow_witness: builder.add_virtual_target(), + }, + }; + + ProofTarget { + wires_root, + plonk_zs_root, + quotient_polys_root, + openings, + opening_proof, + } + } + + fn set_proof_target, const D: usize>( + proof: &Proof, + pt: &ProofTarget, + pw: &mut PartialWitness, + ) { + pw.set_hash_target(pt.wires_root, proof.wires_root); + pw.set_hash_target(pt.plonk_zs_root, proof.plonk_zs_root); + pw.set_hash_target(pt.quotient_polys_root, proof.quotient_polys_root); + + for (&t, &x) in pt.openings.wires.iter().zip(&proof.openings.wires) { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt.openings.constants.iter().zip(&proof.openings.constants) { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .plonk_sigmas + .iter() + .zip(&proof.openings.plonk_s_sigmas) + { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt.openings.plonk_zs.iter().zip(&proof.openings.plonk_zs) { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .plonk_zs_right + .iter() + .zip(&proof.openings.plonk_zs_right) + { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .partial_products + .iter() + .zip(&proof.openings.partial_products) + { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .quotient_polys + .iter() + .zip(&proof.openings.quotient_polys) + { + pw.set_extension_target(t, x); + } + + let fri_proof = &proof.opening_proof.fri_proof; + let fpt = &pt.opening_proof.fri_proof; + + pw.set_target(fpt.pow_witness, fri_proof.pow_witness); + + for (&t, &x) in fpt.final_poly.0.iter().zip(&fri_proof.final_poly.coeffs) { + pw.set_extension_target(t, x); + } + + for (&t, &x) in fpt + .commit_phase_merkle_roots + .iter() + .zip(&fri_proof.commit_phase_merkle_roots) + { + pw.set_hash_target(t, x); + } + + for (qt, q) in fpt + .query_round_proofs + .iter() + .zip(&fri_proof.query_round_proofs) + { + for (at, a) in qt + .initial_trees_proof + .evals_proofs + .iter() + .zip(&q.initial_trees_proof.evals_proofs) + { + for (&t, &x) in at.0.iter().zip(&a.0) { + pw.set_target(t, x); + } + for (&t, &x) in at.1.siblings.iter().zip(&a.1.siblings) { + pw.set_hash_target(t, x); + } + } + + for (st, s) in qt.steps.iter().zip(&q.steps) { + for (&t, &x) in st.evals.iter().zip(&s.evals) { + pw.set_extension_target(t, x); + } + for (&t, &x) in st + .merkle_proof + .siblings + .iter() + .zip(&s.merkle_proof.siblings) + { + pw.set_hash_target(t, x); + } + } + } + } + + #[test] + fn test_recursive_verifier() { + type F = CrandallField; + type FF = QuarticCrandallField; + let proof = { + let config = CircuitConfig::large_config(); + let mut builder = CircuitBuilder::::new(config); + let zero = builder.zero(); + let data = builder.build(); + data.prove(PartialWitness::new()) + }; + + let config = CircuitConfig::large_config(); + let mut builder = CircuitBuilder::::new(config); + let mut pw = PartialWitness::new(); + let pt = proof_to_proof_target(&proof, &mut builder); + set_proof_target(&proof, &pt, &mut pw); + } } diff --git a/src/witness.rs b/src/witness.rs index 863ee7dd..c8705803 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -7,6 +7,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::gates::gate::GateInstance; +use crate::proof::{Hash, HashTarget}; use crate::target::Target; use crate::wire::Wire; @@ -142,6 +143,13 @@ impl PartialWitness { } } + pub fn set_hash_target(&mut self, ht: HashTarget, value: Hash) { + ht.elements + .into_iter() + .zip(value.elements) + .for_each(|(&t, x)| self.set_target(t, x)); + } + pub fn set_extension_target( &mut self, et: ExtensionTarget, From cbb0cbffb16d6df0ed8b329a6cd51a8a5de20f07 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 9 Jul 2021 10:01:58 +0200 Subject: [PATCH 02/21] Finish test setup --- src/circuit_data.rs | 7 +-- src/recursive_verifier.rs | 102 +++++++++++++++++++++++--------------- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 10c5ffe0..e03a6977 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -222,9 +222,6 @@ impl, const D: usize> CommonCircuitData { /// limited form of dynamic inner circuits. We can't practically make things like the wire count /// dynamic, at least not without setting a maximum wire count and paying for the worst case. pub struct VerifierCircuitTarget { - /// A commitment to each constant polynomial. - pub(crate) constants_root: HashTarget, - - /// A commitment to each permutation polynomial. - pub(crate) sigmas_root: HashTarget, + /// A commitment to each constant polynomial and each permutation polynomial. + pub(crate) constants_sigmas_root: HashTarget, } diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 91ab2cd6..228ad38a 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -1,7 +1,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::{CircuitConfig, VerifierCircuitTarget}; use crate::field::extension_field::Extendable; -use crate::gates::gate::GateRef; +use crate::gates::gate::{GateRef, PrefixedGate}; use crate::proof::ProofTarget; const MIN_WIRES: usize = 120; // TODO: Double check. @@ -11,10 +11,10 @@ impl, const D: usize> CircuitBuilder { /// Recursively verifies an inner proof. pub fn add_recursive_verifier( &mut self, - inner_config: CircuitConfig, - inner_circuit: VerifierCircuitTarget, - inner_gates: Vec>, inner_proof: ProofTarget, + inner_config: &CircuitConfig, + inner_circuit_data: &VerifierCircuitTarget, + inner_gates: &[PrefixedGate], ) { assert!(self.config.num_wires >= MIN_WIRES); assert!(self.config.num_wires >= MIN_ROUTED_WIRES); @@ -35,30 +35,13 @@ mod tests { FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, HashTarget, OpeningSetTarget, Proof, }; + use crate::verifier::verify; use crate::witness::PartialWitness; - fn proof_to_proof_target, const D: usize>( + fn get_fri_query_round, const D: usize>( proof: &Proof, builder: &mut CircuitBuilder, - ) -> ProofTarget { - let wires_root = builder.add_virtual_hash(); - let plonk_zs_root = builder.add_virtual_hash(); - let quotient_polys_root = builder.add_virtual_hash(); - - let openings = OpeningSetTarget { - constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), - plonk_sigmas: builder - .add_virtual_extension_targets(proof.openings.plonk_s_sigmas.len()), - wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), - plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), - plonk_zs_right: builder - .add_virtual_extension_targets(proof.openings.plonk_zs_right.len()), - partial_products: builder - .add_virtual_extension_targets(proof.openings.partial_products.len()), - quotient_polys: builder - .add_virtual_extension_targets(proof.openings.quotient_polys.len()), - }; - + ) -> FriQueryRoundTarget { let mut query_round = FriQueryRoundTarget { initial_trees_proof: FriInitialTreeProofTarget { evals_proofs: vec![], @@ -84,22 +67,45 @@ mod tests { }, }); } + query_round + } + fn proof_to_proof_target, const D: usize>( + proof: &Proof, + builder: &mut CircuitBuilder, + ) -> ProofTarget { + let wires_root = builder.add_virtual_hash(); + let plonk_zs_root = builder.add_virtual_hash(); + let quotient_polys_root = builder.add_virtual_hash(); + + let openings = OpeningSetTarget { + constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), + plonk_sigmas: builder + .add_virtual_extension_targets(proof.openings.plonk_s_sigmas.len()), + wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), + plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), + plonk_zs_right: builder + .add_virtual_extension_targets(proof.openings.plonk_zs_right.len()), + partial_products: builder + .add_virtual_extension_targets(proof.openings.partial_products.len()), + quotient_polys: builder + .add_virtual_extension_targets(proof.openings.quotient_polys.len()), + }; + let query_round_proofs = (0..proof.opening_proof.fri_proof.query_round_proofs.len()) + .map(|_| get_fri_query_round(proof, builder)) + .collect(); + let commit_phase_merkle_roots = (0..proof + .opening_proof + .fri_proof + .commit_phase_merkle_roots + .len()) + .map(|_| builder.add_virtual_hash()) + .collect(); let opening_proof = OpeningProofTarget { fri_proof: FriProofTarget { - commit_phase_merkle_roots: vec![ - builder.add_virtual_hash(); - proof - .opening_proof - .fri_proof - .commit_phase_merkle_roots - .len() - ], - query_round_proofs: vec![ - query_round.clone(); - proof.opening_proof.fri_proof.query_round_proofs.len() - ], + commit_phase_merkle_roots, + query_round_proofs, final_poly: PolynomialCoeffsExtTarget(builder.add_virtual_extension_targets( proof.opening_proof.fri_proof.final_poly.len(), )), @@ -223,18 +229,36 @@ mod tests { fn test_recursive_verifier() { type F = CrandallField; type FF = QuarticCrandallField; - let proof = { + let (proof, vd, cd) = { let config = CircuitConfig::large_config(); let mut builder = CircuitBuilder::::new(config); let zero = builder.zero(); let data = builder.build(); - data.prove(PartialWitness::new()) + ( + data.prove(PartialWitness::new()), + data.verifier_only, + data.common, + ) }; let config = CircuitConfig::large_config(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); let pt = proof_to_proof_target(&proof, &mut builder); set_proof_target(&proof, &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); + + let gates = cd.gates; + + builder.add_recursive_verifier(pt, &config, &inner_data, &gates); + + let data = builder.build(); + let recursive_proof = data.prove(PartialWitness::new()); + + verify(recursive_proof, &data.verifier_only, &data.common).unwrap(); } } From ad24f5d4d1206fc13563b4f52074a6216c6797c0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 12 Jul 2021 14:25:28 +0200 Subject: [PATCH 03/21] Almost working recursive verifier --- src/fri/recursive_verifier.rs | 4 +- src/fri/verifier.rs | 2 +- src/gadgets/arithmetic_extension.rs | 10 + src/gadgets/insert.rs | 7 +- src/gates/gate.rs | 28 ++- src/generator.rs | 6 + src/lib.rs | 1 + src/plonk_challenger.rs | 29 ++- src/plonk_common.rs | 253 ++------------------ src/polynomial/commitment.rs | 40 +++- src/proof.rs | 10 +- src/prover.rs | 9 +- src/recursive_verifier.rs | 111 ++++++++- src/util/partial_products.rs | 29 +++ src/vanishing_poly.rs | 356 ++++++++++++++++++++++++++++ src/vars.rs | 6 + src/verifier.rs | 5 +- 17 files changed, 643 insertions(+), 263 deletions(-) create mode 100644 src/vanishing_poly.rs diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 31ab0a25..fad2317c 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -1,6 +1,7 @@ use itertools::izip; use crate::circuit_builder::CircuitBuilder; +use crate::circuit_data::CommonCircuitData; use crate::field::extension_field::target::{flatten_target, ExtensionTarget}; use crate::field::extension_field::Extendable; use crate::field::field::Field; @@ -73,8 +74,9 @@ impl, const D: usize> CircuitBuilder { initial_merkle_roots: &[HashTarget], proof: &FriProofTarget, challenger: &mut RecursiveChallenger, - config: &FriConfig, + common_data: &CommonCircuitData, ) { + let config = &common_data.config.fri_config; let total_arities = config.reduction_arity_bits.iter().sum::(); debug_assert_eq!( purported_degree_log, diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index e0716cde..5ff068b6 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -178,7 +178,7 @@ fn fri_combine_initial, const D: usize>( let single_openings = os .constants .iter() - .chain(&os.plonk_s_sigmas) + .chain(&os.plonk_sigmas) .chain(&os.quotient_polys) .chain(&os.partial_products); let single_diffs = single_evals diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 3bf9c8a9..57968a23 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -252,6 +252,16 @@ impl, const D: usize> CircuitBuilder { self.arithmetic_extension(F::ONE, F::ONE, a_ext, b, c) } + /// Like `mul_sub`, but for `ExtensionTarget`s. + pub fn mul_sub_extension( + &mut self, + a: ExtensionTarget, + b: ExtensionTarget, + c: ExtensionTarget, + ) -> ExtensionTarget { + self.arithmetic_extension(F::ONE, F::NEG_ONE, a, b, c) + } + /// Like `mul_sub`, but for `ExtensionTarget`s. pub fn scalar_mul_sub_extension( &mut self, diff --git a/src/gadgets/insert.rs b/src/gadgets/insert.rs index 29e360fc..aee4dcd3 100644 --- a/src/gadgets/insert.rs +++ b/src/gadgets/insert.rs @@ -49,7 +49,7 @@ impl, const D: usize> CircuitBuilder { let mut already_inserted = self.zero(); let mut new_list = Vec::new(); - for i in 0..v.len() { + for i in 0..=v.len() { let one = self.one(); let cur_index = self.constant(F::from_canonical_usize(i)); @@ -63,7 +63,9 @@ impl, const D: usize> CircuitBuilder { already_inserted = self.add(already_inserted, insert_here); let not_already_inserted = self.sub(one, already_inserted); - new_item = self.scalar_mul_add_extension(not_already_inserted, v[i], new_item); + if i < v.len() { + new_item = self.scalar_mul_add_extension(not_already_inserted, v[i], new_item); + } new_list.push(new_item); } @@ -106,6 +108,7 @@ mod tests { let elem = builder.constant_extension(FF::rand()); let inserted = real_insert(i, elem, &v); let purported_inserted = builder.insert(it, elem, v.clone()); + assert_eq!(inserted.len(), purported_inserted.len()); for (x, y) in inserted.into_iter().zip(purported_inserted) { builder.route_extension(x, y); diff --git a/src/gates/gate.rs b/src/gates/gate.rs index 4b37892c..cce665f9 100644 --- a/src/gates/gate.rs +++ b/src/gates/gate.rs @@ -8,6 +8,7 @@ use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::gates::gate_tree::Tree; use crate::generator::WitnessGenerator; +use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A custom gate. @@ -76,9 +77,11 @@ pub trait Gate, const D: usize>: 'static + Send + Sync { fn eval_filtered_recursively( &self, builder: &mut CircuitBuilder, - vars: EvaluationTargets, + mut vars: EvaluationTargets, + prefix: &[bool], ) -> Vec> { - // TODO: Filter + let filter = compute_filter_recursively(builder, prefix, vars.local_constants); + vars.remove_prefix(prefix); self.eval_unfiltered_recursively(builder, vars) } @@ -167,3 +170,24 @@ fn compute_filter(prefix: &[bool], constants: &[K]) -> K { }) .product() } + +fn compute_filter_recursively, const D: usize>( + builder: &mut CircuitBuilder, + prefix: &[bool], + constants: &[ExtensionTarget], +) -> ExtensionTarget { + let one = builder.one_extension(); + let v = prefix + .iter() + .enumerate() + .map(|(i, &b)| { + if b { + constants[i] + } else { + builder.sub_extension(one, constants[i]) + } + }) + .collect::>(); + + builder.mul_many_extension(&v) +} diff --git a/src/generator.rs b/src/generator.rs index a47c5267..ee2001ec 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -55,6 +55,12 @@ pub(crate) fn generate_partial_witness( pending_generator_indices = next_pending_generator_indices; } + for i in 0..generators.len() { + if !expired_generator_indices.contains(&i) { + dbg!(i); + break; + } + } assert_eq!( expired_generator_indices.len(), generators.len(), diff --git a/src/lib.rs b/src/lib.rs index adfdf2cf..50c0bb4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod recursive_verifier; pub mod rescue; pub mod target; pub mod util; +pub mod vanishing_poly; pub mod vars; pub mod verifier; pub mod wire; diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index 149dceb3..da7253f0 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -5,7 +5,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::hash::{permute, SPONGE_RATE, SPONGE_WIDTH}; -use crate::proof::{Hash, HashTarget, OpeningSet}; +use crate::proof::{Hash, HashTarget, OpeningSet, OpeningSetTarget}; use crate::target::Target; /// Observes prover messages, and generates challenges by hashing the transcript. @@ -68,7 +68,7 @@ impl Challenger { { let OpeningSet { constants, - plonk_s_sigmas, + plonk_sigmas, wires, plonk_zs, plonk_zs_right, @@ -77,7 +77,7 @@ impl Challenger { } = os; for v in &[ constants, - plonk_s_sigmas, + plonk_sigmas, wires, plonk_zs, plonk_zs_right, @@ -211,6 +211,29 @@ impl RecursiveChallenger { } } + pub fn observe_opening_set(&mut self, os: &OpeningSetTarget) { + let OpeningSetTarget { + constants, + plonk_sigmas, + wires, + plonk_zs, + plonk_zs_right, + partial_products, + quotient_polys, + } = os; + for v in &[ + constants, + plonk_sigmas, + wires, + plonk_zs, + plonk_zs_right, + partial_products, + quotient_polys, + ] { + self.observe_extension_elements(v); + } + } + pub fn observe_hash(&mut self, hash: &HashTarget) { self.observe_elements(&hash.elements) } diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 5179b474..2c3a0817 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -58,237 +58,6 @@ impl PlonkPolynomials { } } -/// 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 -/// argument. All such terms should vanish on `H`. -pub(crate) fn eval_vanishing_poly, const D: usize>( - common_data: &CommonCircuitData, - x: F::Extension, - vars: EvaluationVars, - local_zs: &[F::Extension], - next_zs: &[F::Extension], - partial_products: &[F::Extension], - s_sigmas: &[F::Extension], - betas: &[F], - gammas: &[F], - alphas: &[F], -) -> Vec { - let max_degree = common_data.quotient_degree_factor; - let (num_prods, final_num_prod) = common_data.num_partial_products; - - let constraint_terms = - evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars); - - // The L_1(x) (Z(x) - 1) vanishing terms. - let mut vanishing_z_1_terms = Vec::new(); - // The terms checking the partial products. - let mut vanishing_partial_products_terms = Vec::new(); - // The Z(x) f'(x) - g'(x) Z(g x) terms. - let mut vanishing_v_shift_terms = Vec::new(); - - for i in 0..common_data.config.num_challenges { - let z_x = local_zs[i]; - let z_gz = next_zs[i]; - vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::Extension::ONE)); - - let numerator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let k_i = common_data.k_is[j]; - let s_id = x * k_i.into(); - wire_value + s_id * betas[i].into() + gammas[i].into() - }) - .collect::>(); - let denominator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let s_sigma = s_sigmas[j]; - wire_value + s_sigma * betas[i].into() + gammas[i].into() - }) - .collect::>(); - let quotient_values = (0..common_data.config.num_routed_wires) - .map(|j| numerator_values[j] / denominator_values[j]) - .collect::>(); - - // The partial products considered for this iteration of `i`. - let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; - // Check the quotient partial products. - let mut partial_product_check = - check_partial_products("ient_values, current_partial_products, max_degree); - // The first checks are of the form `q - n/d` which is a rational function not a polynomial. - // We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials. - denominator_values - .chunks(max_degree) - .zip(partial_product_check.iter_mut()) - .for_each(|(d, q)| { - *q *= d.iter().copied().product(); - }); - vanishing_partial_products_terms.extend(partial_product_check); - - // The quotient final product is the product of the last `final_num_prod` elements. - let quotient: F::Extension = current_partial_products[num_prods - final_num_prod..] - .iter() - .copied() - .product(); - vanishing_v_shift_terms.push(quotient * z_x - z_gz); - } - - let vanishing_terms = [ - vanishing_z_1_terms, - vanishing_partial_products_terms, - vanishing_v_shift_terms, - constraint_terms, - ] - .concat(); - - let alphas = &alphas.iter().map(|&a| a.into()).collect::>(); - reduce_with_powers_multi(&vanishing_terms, alphas) -} - -/// Like `eval_vanishing_poly`, but specialized for base field points. -pub(crate) fn eval_vanishing_poly_base, const D: usize>( - common_data: &CommonCircuitData, - index: usize, - x: F, - vars: EvaluationVarsBase, - local_zs: &[F], - next_zs: &[F], - partial_products: &[F], - s_sigmas: &[F], - betas: &[F], - gammas: &[F], - alphas: &[F], - z_h_on_coset: &ZeroPolyOnCoset, -) -> Vec { - let max_degree = common_data.quotient_degree_factor; - let (num_prods, final_num_prod) = common_data.num_partial_products; - - let constraint_terms = - evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars); - - // The L_1(x) (Z(x) - 1) vanishing terms. - let mut vanishing_z_1_terms = Vec::new(); - // The terms checking the partial products. - let mut vanishing_partial_products_terms = Vec::new(); - // The Z(x) f'(x) - g'(x) Z(g x) terms. - let mut vanishing_v_shift_terms = Vec::new(); - - for i in 0..common_data.config.num_challenges { - let z_x = local_zs[i]; - let z_gz = next_zs[i]; - vanishing_z_1_terms.push(z_h_on_coset.eval_l1(index, x) * (z_x - F::ONE)); - - let numerator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let k_i = common_data.k_is[j]; - let s_id = k_i * x; - wire_value + betas[i] * s_id + gammas[i] - }) - .collect::>(); - let denominator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let s_sigma = s_sigmas[j]; - wire_value + betas[i] * s_sigma + gammas[i] - }) - .collect::>(); - let quotient_values = (0..common_data.config.num_routed_wires) - .map(|j| numerator_values[j] / denominator_values[j]) - .collect::>(); - - // The partial products considered for this iteration of `i`. - let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; - // Check the numerator partial products. - let mut partial_product_check = - check_partial_products("ient_values, current_partial_products, max_degree); - // The first checks are of the form `q - n/d` which is a rational function not a polynomial. - // We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials. - denominator_values - .chunks(max_degree) - .zip(partial_product_check.iter_mut()) - .for_each(|(d, q)| { - *q *= d.iter().copied().product(); - }); - vanishing_partial_products_terms.extend(partial_product_check); - - // The quotient final product is the product of the last `final_num_prod` elements. - let quotient: F = current_partial_products[num_prods - final_num_prod..] - .iter() - .copied() - .product(); - vanishing_v_shift_terms.push(quotient * z_x - z_gz); - } - let vanishing_terms = [ - vanishing_z_1_terms, - vanishing_partial_products_terms, - vanishing_v_shift_terms, - constraint_terms, - ] - .concat(); - - reduce_with_powers_multi(&vanishing_terms, alphas) -} - -/// Evaluates all gate constraints. -/// -/// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not -/// strictly necessary, but it helps performance by ensuring that we allocate a vector with exactly -/// the capacity that we need. -pub fn evaluate_gate_constraints, const D: usize>( - gates: &[PrefixedGate], - num_gate_constraints: usize, - vars: EvaluationVars, -) -> Vec { - let mut constraints = vec![F::Extension::ZERO; num_gate_constraints]; - for gate in gates { - let gate_constraints = gate.gate.0.eval_filtered(vars, &gate.prefix); - for (i, c) in gate_constraints.into_iter().enumerate() { - debug_assert!( - i < num_gate_constraints, - "num_constraints() gave too low of a number" - ); - constraints[i] += c; - } - } - constraints -} - -pub fn evaluate_gate_constraints_base, const D: usize>( - gates: &[PrefixedGate], - num_gate_constraints: usize, - vars: EvaluationVarsBase, -) -> Vec { - let mut constraints = vec![F::ZERO; num_gate_constraints]; - for gate in gates { - let gate_constraints = gate.gate.0.eval_filtered_base(vars, &gate.prefix); - for (i, c) in gate_constraints.into_iter().enumerate() { - debug_assert!( - i < num_gate_constraints, - "num_constraints() gave too low of a number" - ); - constraints[i] += c; - } - } - constraints -} - -pub fn evaluate_gate_constraints_recursively, const D: usize>( - builder: &mut CircuitBuilder, - gates: &[GateRef], - num_gate_constraints: usize, - vars: EvaluationTargets, -) -> Vec> { - let mut constraints = vec![builder.zero_extension(); num_gate_constraints]; - for gate in gates { - let gate_constraints = gate.0.eval_filtered_recursively(builder, vars); - for (i, c) in gate_constraints.into_iter().enumerate() { - constraints[i] = builder.add_extension(constraints[i], c); - } - } - constraints -} - /// Evaluate the polynomial which vanishes on any multiplicative subgroup of a given order `n`. pub(crate) fn eval_zero_poly(n: usize, x: F) -> F { // Z(x) = x^n - 1 @@ -354,6 +123,28 @@ pub(crate) fn eval_l_1(n: usize, x: F) -> F { eval_zero_poly(n, x) / (F::from_canonical_usize(n) * (x - F::ONE)) } +pub(crate) fn eval_l_1_recursively, const D: usize>( + builder: &mut CircuitBuilder, + n: usize, + x: ExtensionTarget, + x_pow_n: ExtensionTarget, +) -> ExtensionTarget { + // L_1(x) = (x^n - 1) / (n * (x - 1)) + // = Z(x) / (n * (x - 1)) + let one = builder.one_extension(); + let neg_one = builder.neg_one(); + let neg_one = builder.convert_to_ext(neg_one); + let eval_zero_poly = builder.sub_extension(x_pow_n, one); + let denominator = builder.arithmetic_extension( + F::from_canonical_usize(n), + F::from_canonical_usize(n), + x, + one, + neg_one, + ); + builder.div_unsafe_extension(eval_zero_poly, denominator) +} + /// For each alpha in alphas, compute a reduction of the given terms using powers of alpha. pub(crate) fn reduce_with_powers_multi(terms: &[F], alphas: &[F]) -> Vec { alphas diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 286f03c9..bb6f0e4e 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -1,19 +1,21 @@ use anyhow::Result; use rayon::prelude::*; +use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CommonCircuitData; +use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; -use crate::plonk_challenger::Challenger; +use crate::plonk_challenger::{Challenger, RecursiveChallenger}; use crate::plonk_common::PlonkPolynomials; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; -use crate::proof::{FriProof, FriProofTarget, Hash, OpeningSet}; +use crate::proof::{FriProof, FriProofTarget, Hash, HashTarget, OpeningSet, OpeningSetTarget}; use crate::timed; use crate::util::scaling::ReducingFactor; -use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place, transpose}; +use crate::util::{log2_ceil, log2_strict, reverse_bits, reverse_index_bits_in_place, transpose}; pub const SALT_SIZE: usize = 2; @@ -245,13 +247,14 @@ impl ListPolynomialCommitment { } } -pub struct OpeningProof, const D: usize> { +#[derive(Clone)] +pub struct OpeningProof, const D: usize> { pub fri_proof: FriProof, // TODO: Get the degree from `CommonCircuitData` instead. quotient_degree: usize, } -impl, const D: usize> OpeningProof { +impl, const D: usize> OpeningProof { pub fn verify( &self, zeta: F::Extension, @@ -281,6 +284,33 @@ pub struct OpeningProofTarget { pub fri_proof: FriProofTarget, } +impl OpeningProofTarget { + pub fn verify>( + &self, + zeta: ExtensionTarget, + os: &OpeningSetTarget, + merkle_roots: &[HashTarget], + challenger: &mut RecursiveChallenger, + common_data: &CommonCircuitData, + builder: &mut CircuitBuilder, + ) { + challenger.observe_opening_set(os); + + let alpha = challenger.get_extension_challenge(builder); + + builder.verify_fri_proof( + log2_ceil(common_data.degree()), + &os, + zeta, + alpha, + merkle_roots, + &self.fri_proof, + challenger, + common_data, + ); + } +} + #[cfg(test)] mod tests { use anyhow::Result; diff --git a/src/proof.rs b/src/proof.rs index 2c83fb33..353a0080 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -61,6 +61,7 @@ impl HashTarget { } } +#[derive(Clone)] pub struct Proof, const D: usize> { /// Merkle root of LDEs of wire values. pub wires_root: Hash, @@ -83,6 +84,7 @@ pub struct ProofTarget { } /// Evaluations and Merkle proof produced by the prover in a FRI query step. +#[derive(Clone)] pub struct FriQueryStep, const D: usize> { pub evals: Vec, pub merkle_proof: MerkleProof, @@ -96,6 +98,7 @@ pub struct FriQueryStepTarget { /// Evaluations and Merkle proofs of the original set of polynomials, /// before they are combined into a composition polynomial. +#[derive(Clone)] pub struct FriInitialTreeProof { pub evals_proofs: Vec<(Vec, MerkleProof)>, } @@ -120,6 +123,7 @@ impl FriInitialTreeProofTarget { } /// Proof for a FRI query round. +#[derive(Clone)] pub struct FriQueryRound, const D: usize> { pub initial_trees_proof: FriInitialTreeProof, pub steps: Vec>, @@ -131,6 +135,7 @@ pub struct FriQueryRoundTarget { pub steps: Vec>, } +#[derive(Clone)] pub struct FriProof, const D: usize> { /// A Merkle root for each reduced polynomial in the commit phase. pub commit_phase_merkle_roots: Vec>, @@ -153,7 +158,7 @@ pub struct FriProofTarget { /// The purported values of each polynomial at a single point. pub struct OpeningSet, const D: usize> { pub constants: Vec, - pub plonk_s_sigmas: Vec, + pub plonk_sigmas: Vec, pub wires: Vec, pub plonk_zs: Vec, pub plonk_zs_right: Vec, @@ -181,7 +186,7 @@ impl, const D: usize> OpeningSet { let zs_partial_products_eval = eval_commitment(z, zs_partial_products_commitment); Self { constants: constants_sigmas_eval[common_data.constants_range()].to_vec(), - plonk_s_sigmas: constants_sigmas_eval[common_data.sigmas_range()].to_vec(), + plonk_sigmas: constants_sigmas_eval[common_data.sigmas_range()].to_vec(), wires: eval_commitment(z, wires_commitment), plonk_zs: zs_partial_products_eval[common_data.zs_range()].to_vec(), plonk_zs_right: eval_commitment(g * z, zs_partial_products_commitment) @@ -195,6 +200,7 @@ impl, const D: usize> OpeningSet { } /// The purported values of each polynomial at a single point. +#[derive(Clone, Debug)] pub struct OpeningSetTarget { pub constants: Vec>, pub plonk_sigmas: Vec>, diff --git a/src/prover.rs b/src/prover.rs index 63c32995..8194551f 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -7,13 +7,14 @@ use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; use crate::field::extension_field::Extendable; use crate::generator::generate_partial_witness; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{eval_vanishing_poly_base, PlonkPolynomials, ZeroPolyOnCoset}; +use crate::plonk_common::{PlonkPolynomials, ZeroPolyOnCoset}; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::Proof; use crate::timed; use crate::util::partial_products::partial_products; use crate::util::{log2_ceil, transpose}; +use crate::vanishing_poly::eval_vanishing_poly_base; use crate::vars::EvaluationVarsBase; use crate::witness::{PartialWitness, Witness}; @@ -50,6 +51,12 @@ pub(crate) fn prove, const D: usize>( "to check copy constraints" ); + if degree > 7 { + dbg!(witness.get_wire(8, 16)); + dbg!(witness.get_wire(8, 17)); + dbg!(witness.get_wire(8, 18)); + dbg!(witness.get_wire(8, 19)); + } let wires_values: Vec> = timed!( witness .wire_values diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 228ad38a..33912663 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -1,8 +1,15 @@ +use env_logger::builder; + use crate::circuit_builder::CircuitBuilder; -use crate::circuit_data::{CircuitConfig, VerifierCircuitTarget}; +use crate::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; use crate::field::extension_field::Extendable; +use crate::field::field::Field; use crate::gates::gate::{GateRef, PrefixedGate}; -use crate::proof::ProofTarget; +use crate::plonk_challenger::RecursiveChallenger; +use crate::proof::{HashTarget, ProofTarget}; +use crate::util::scaling::ReducingFactorTarget; +use crate::vanishing_poly::eval_vanishing_poly_recursively; +use crate::vars::EvaluationTargets; const MIN_WIRES: usize = 120; // TODO: Double check. const MIN_ROUTED_WIRES: usize = 28; // TODO: Double check. @@ -11,15 +18,94 @@ impl, const D: usize> CircuitBuilder { /// Recursively verifies an inner proof. pub fn add_recursive_verifier( &mut self, - inner_proof: ProofTarget, + proof: ProofTarget, inner_config: &CircuitConfig, - inner_circuit_data: &VerifierCircuitTarget, - inner_gates: &[PrefixedGate], + inner_verifier_data: &VerifierCircuitTarget, + inner_common_data: &CommonCircuitData, ) { assert!(self.config.num_wires >= MIN_WIRES); assert!(self.config.num_wires >= MIN_ROUTED_WIRES); + let one = self.one_extension(); - todo!() + let num_challenges = inner_config.num_challenges; + + let mut challenger = RecursiveChallenger::new(self); + + let digest = + HashTarget::from_vec(self.constants(&inner_common_data.circuit_digest.elements)); + challenger.observe_hash(&digest); + + challenger.observe_hash(&proof.wires_root); + let betas = challenger.get_n_challenges(self, num_challenges); + let gammas = challenger.get_n_challenges(self, num_challenges); + + challenger.observe_hash(&proof.plonk_zs_root); + let alphas = challenger.get_n_challenges(self, num_challenges); + + challenger.observe_hash(&proof.quotient_polys_root); + let zeta = challenger.get_extension_challenge(self); + + let local_constants = &proof.openings.constants; + let local_wires = &proof.openings.wires; + let vars = EvaluationTargets { + local_constants, + local_wires, + }; + let local_zs = &proof.openings.plonk_zs; + let next_zs = &proof.openings.plonk_zs_right; + let s_sigmas = &proof.openings.plonk_sigmas; + let partial_products = &proof.openings.partial_products; + + let zeta_pow_deg = self.exp_u64_extension(zeta, inner_common_data.degree() as u64); + // Evaluate the vanishing polynomial at our challenge point, zeta. + let vanishing_polys_zeta = eval_vanishing_poly_recursively( + self, + inner_common_data, + zeta, + zeta_pow_deg, + vars, + local_zs, + next_zs, + partial_products, + s_sigmas, + &betas, + &gammas, + &alphas, + ); + + // let quotient_polys_zeta = &proof.openings.quotient_polys; + // let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); + // let z_h_zeta = self.sub_extension(zeta_pow_deg, one); + // for (i, chunk) in quotient_polys_zeta + // .chunks(inner_common_data.quotient_degree_factor) + // .enumerate() + // { + // 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); + // } + // + // let evaluations = proof.openings.clone(); + // + // let merkle_roots = &[ + // inner_verifier_data.constants_sigmas_root, + // proof.wires_root, + // proof.plonk_zs_root, + // proof.quotient_polys_root, + // ]; + // + // proof.opening_proof.verify( + // zeta, + // &evaluations, + // merkle_roots, + // &mut challenger, + // inner_common_data, + // self, + // ); + // dbg!(self.num_gates()); + // dbg!(self.generators.len()); } } @@ -80,8 +166,7 @@ mod tests { let openings = OpeningSetTarget { constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), - plonk_sigmas: builder - .add_virtual_extension_targets(proof.openings.plonk_s_sigmas.len()), + plonk_sigmas: builder.add_virtual_extension_targets(proof.openings.plonk_sigmas.len()), wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), plonk_zs_right: builder @@ -141,7 +226,7 @@ mod tests { .openings .plonk_sigmas .iter() - .zip(&proof.openings.plonk_s_sigmas) + .zip(&proof.openings.plonk_sigmas) { pw.set_extension_target(t, x); } @@ -240,6 +325,7 @@ mod tests { data.common, ) }; + verify(proof.clone(), &vd, &cd).unwrap(); let config = CircuitConfig::large_config(); let mut builder = CircuitBuilder::::new(config.clone()); @@ -252,12 +338,11 @@ mod tests { }; pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); - let gates = cd.gates; - - builder.add_recursive_verifier(pt, &config, &inner_data, &gates); + builder.add_recursive_verifier(pt, &config, &inner_data, &cd); + dbg!(builder.num_gates()); let data = builder.build(); - let recursive_proof = data.prove(PartialWitness::new()); + let recursive_proof = data.prove(pw); verify(recursive_proof, &data.verifier_only, &data.common).unwrap(); } diff --git a/src/util/partial_products.rs b/src/util/partial_products.rs index 1d169b8d..ed87002e 100644 --- a/src/util/partial_products.rs +++ b/src/util/partial_products.rs @@ -1,6 +1,9 @@ use std::iter::Product; use std::ops::Sub; +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::Extendable; use crate::util::ceil_div_usize; /// Compute partial products of the original vector `v` such that all products consist of `max_degree` @@ -58,6 +61,32 @@ pub fn check_partial_products>( res } +pub fn check_partial_products_recursively, const D: usize>( + builder: &mut CircuitBuilder, + v: &[ExtensionTarget], + partials: &[ExtensionTarget], + max_degree: usize, +) -> Vec> { + let mut res = Vec::new(); + let mut remainder = v.to_vec(); + let mut partials = partials.to_vec(); + while remainder.len() > max_degree { + let products = remainder + .chunks(max_degree) + .map(|chunk| builder.mul_many_extension(chunk)) + .collect::>(); + res.extend( + products + .iter() + .zip(&partials) + .map(|(&a, &b)| builder.sub_extension(a, b)), + ); + remainder = partials.drain(..products.len()).collect(); + } + + res +} + #[cfg(test)] mod tests { use num::Zero; diff --git a/src/vanishing_poly.rs b/src/vanishing_poly.rs new file mode 100644 index 00000000..a5f63ac2 --- /dev/null +++ b/src/vanishing_poly.rs @@ -0,0 +1,356 @@ +use crate::circuit_builder::CircuitBuilder; +use crate::circuit_data::CommonCircuitData; +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::Extendable; +use crate::field::field::Field; +use crate::gates::gate::{Gate, GateRef, PrefixedGate}; +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::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; + +/// 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 +/// argument. All such terms should vanish on `H`. +pub(crate) fn eval_vanishing_poly, const D: usize>( + common_data: &CommonCircuitData, + x: F::Extension, + vars: EvaluationVars, + local_zs: &[F::Extension], + next_zs: &[F::Extension], + partial_products: &[F::Extension], + s_sigmas: &[F::Extension], + betas: &[F], + gammas: &[F], + alphas: &[F], +) -> Vec { + let max_degree = common_data.quotient_degree_factor; + let (num_prods, final_num_prod) = common_data.num_partial_products; + + let constraint_terms = + evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars); + + // The L_1(x) (Z(x) - 1) vanishing terms. + let mut vanishing_z_1_terms = Vec::new(); + // The terms checking the partial products. + let mut vanishing_partial_products_terms = Vec::new(); + // The Z(x) f'(x) - g'(x) Z(g x) terms. + let mut vanishing_v_shift_terms = Vec::new(); + + for i in 0..common_data.config.num_challenges { + let z_x = local_zs[i]; + let z_gz = next_zs[i]; + vanishing_z_1_terms + .push(plonk_common::eval_l_1(common_data.degree(), x) * (z_x - F::Extension::ONE)); + + let numerator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let k_i = common_data.k_is[j]; + let s_id = x * k_i.into(); + wire_value + s_id * betas[i].into() + gammas[i].into() + }) + .collect::>(); + let denominator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let s_sigma = s_sigmas[j]; + wire_value + s_sigma * betas[i].into() + gammas[i].into() + }) + .collect::>(); + let quotient_values = (0..common_data.config.num_routed_wires) + .map(|j| numerator_values[j] / denominator_values[j]) + .collect::>(); + + // The partial products considered for this iteration of `i`. + let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; + // Check the quotient partial products. + let mut partial_product_check = + check_partial_products("ient_values, current_partial_products, max_degree); + // The first checks are of the form `q - n/d` which is a rational function not a polynomial. + // We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials. + denominator_values + .chunks(max_degree) + .zip(partial_product_check.iter_mut()) + .for_each(|(d, q)| { + *q *= d.iter().copied().product(); + }); + vanishing_partial_products_terms.extend(partial_product_check); + + // The quotient final product is the product of the last `final_num_prod` elements. + let quotient: F::Extension = current_partial_products[num_prods - final_num_prod..] + .iter() + .copied() + .product(); + vanishing_v_shift_terms.push(quotient * z_x - z_gz); + } + + let vanishing_terms = [ + vanishing_z_1_terms, + vanishing_partial_products_terms, + vanishing_v_shift_terms, + constraint_terms, + ] + .concat(); + dbg!(&vanishing_terms); + + let alphas = &alphas.iter().map(|&a| a.into()).collect::>(); + plonk_common::reduce_with_powers_multi(&vanishing_terms, alphas) +} + +/// Like `eval_vanishing_poly`, but specialized for base field points. +pub(crate) fn eval_vanishing_poly_base, const D: usize>( + common_data: &CommonCircuitData, + index: usize, + x: F, + vars: EvaluationVarsBase, + local_zs: &[F], + next_zs: &[F], + partial_products: &[F], + s_sigmas: &[F], + betas: &[F], + gammas: &[F], + alphas: &[F], + z_h_on_coset: &ZeroPolyOnCoset, +) -> Vec { + let max_degree = common_data.quotient_degree_factor; + let (num_prods, final_num_prod) = common_data.num_partial_products; + + let constraint_terms = + evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars); + + // The L_1(x) (Z(x) - 1) vanishing terms. + let mut vanishing_z_1_terms = Vec::new(); + // The terms checking the partial products. + let mut vanishing_partial_products_terms = Vec::new(); + // The Z(x) f'(x) - g'(x) Z(g x) terms. + let mut vanishing_v_shift_terms = Vec::new(); + + for i in 0..common_data.config.num_challenges { + let z_x = local_zs[i]; + let z_gz = next_zs[i]; + vanishing_z_1_terms.push(z_h_on_coset.eval_l1(index, x) * (z_x - F::ONE)); + + let numerator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let k_i = common_data.k_is[j]; + let s_id = k_i * x; + wire_value + betas[i] * s_id + gammas[i] + }) + .collect::>(); + let denominator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let s_sigma = s_sigmas[j]; + wire_value + betas[i] * s_sigma + gammas[i] + }) + .collect::>(); + let quotient_values = (0..common_data.config.num_routed_wires) + .map(|j| numerator_values[j] / denominator_values[j]) + .collect::>(); + + // The partial products considered for this iteration of `i`. + let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; + // Check the numerator partial products. + let mut partial_product_check = + check_partial_products("ient_values, current_partial_products, max_degree); + // The first checks are of the form `q - n/d` which is a rational function not a polynomial. + // We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials. + denominator_values + .chunks(max_degree) + .zip(partial_product_check.iter_mut()) + .for_each(|(d, q)| { + *q *= d.iter().copied().product(); + }); + vanishing_partial_products_terms.extend(partial_product_check); + + // The quotient final product is the product of the last `final_num_prod` elements. + let quotient: F = current_partial_products[num_prods - final_num_prod..] + .iter() + .copied() + .product(); + vanishing_v_shift_terms.push(quotient * z_x - z_gz); + } + let vanishing_terms = [ + vanishing_z_1_terms, + vanishing_partial_products_terms, + vanishing_v_shift_terms, + constraint_terms, + ] + .concat(); + + plonk_common::reduce_with_powers_multi(&vanishing_terms, alphas) +} + +/// Evaluates all gate constraints. +/// +/// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not +/// strictly necessary, but it helps performance by ensuring that we allocate a vector with exactly +/// the capacity that we need. +pub fn evaluate_gate_constraints, const D: usize>( + gates: &[PrefixedGate], + num_gate_constraints: usize, + vars: EvaluationVars, +) -> Vec { + let mut constraints = vec![F::Extension::ZERO; num_gate_constraints]; + for gate in gates { + let gate_constraints = gate.gate.0.eval_filtered(vars, &gate.prefix); + for (i, c) in gate_constraints.into_iter().enumerate() { + debug_assert!( + i < num_gate_constraints, + "num_constraints() gave too low of a number" + ); + constraints[i] += c; + } + } + constraints +} + +pub fn evaluate_gate_constraints_base, const D: usize>( + gates: &[PrefixedGate], + num_gate_constraints: usize, + vars: EvaluationVarsBase, +) -> Vec { + let mut constraints = vec![F::ZERO; num_gate_constraints]; + for gate in gates { + let gate_constraints = gate.gate.0.eval_filtered_base(vars, &gate.prefix); + for (i, c) in gate_constraints.into_iter().enumerate() { + debug_assert!( + i < num_gate_constraints, + "num_constraints() gave too low of a number" + ); + constraints[i] += c; + } + } + constraints +} + +pub fn evaluate_gate_constraints_recursively, const D: usize>( + builder: &mut CircuitBuilder, + gates: &[PrefixedGate], + num_gate_constraints: usize, + vars: EvaluationTargets, +) -> Vec> { + let mut constraints = vec![builder.zero_extension(); num_gate_constraints]; + for gate in gates { + let gate_constraints = gate + .gate + .0 + .eval_filtered_recursively(builder, vars, &gate.prefix); + for (i, c) in gate_constraints.into_iter().enumerate() { + constraints[i] = builder.add_extension(constraints[i], c); + } + } + constraints +} + +/// 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 +/// argument. All such terms should vanish on `H`. +pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( + builder: &mut CircuitBuilder, + common_data: &CommonCircuitData, + x: ExtensionTarget, + x_pow_deg: ExtensionTarget, + vars: EvaluationTargets, + local_zs: &[ExtensionTarget], + next_zs: &[ExtensionTarget], + partial_products: &[ExtensionTarget], + s_sigmas: &[ExtensionTarget], + betas: &[Target], + gammas: &[Target], + alphas: &[Target], +) -> Vec> { + let max_degree = common_data.quotient_degree_factor; + let (num_prods, final_num_prod) = common_data.num_partial_products; + + let constraint_terms = evaluate_gate_constraints_recursively( + builder, + &common_data.gates, + common_data.num_gate_constraints, + vars, + ); + + // The L_1(x) (Z(x) - 1) vanishing terms. + let mut vanishing_z_1_terms = Vec::new(); + // The terms checking the partial products. + let mut vanishing_partial_products_terms = Vec::new(); + // The Z(x) f'(x) - g'(x) Z(g x) terms. + let mut vanishing_v_shift_terms = Vec::new(); + + for i in 0..common_data.config.num_challenges { + let z_x = local_zs[i]; + let z_gz = next_zs[i]; + let l1 = eval_l_1_recursively(builder, common_data.degree(), x, x_pow_deg); + vanishing_z_1_terms.push(builder.arithmetic_extension(F::ONE, F::NEG_ONE, l1, z_x, l1)); + + let numerator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let k_i = builder.constant(common_data.k_is[j]); + let s_id = builder.scalar_mul_ext(k_i, x); + let gamma_ext = builder.convert_to_ext(gammas[i]); + let tmp = builder.scalar_mul_add_extension(betas[i], s_id, wire_value); + builder.add_extension(tmp, gamma_ext) + }) + .collect::>(); + let denominator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let s_sigma = s_sigmas[j]; + let gamma_ext = builder.convert_to_ext(gammas[i]); + let tmp = builder.scalar_mul_add_extension(betas[i], s_sigma, wire_value); + builder.add_extension(tmp, gamma_ext) + }) + .collect::>(); + let quotient_values = (0..common_data.config.num_routed_wires) + .map(|j| builder.div_unsafe_extension(numerator_values[j], denominator_values[j])) + .collect::>(); + + // The partial products considered for this iteration of `i`. + let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; + // Check the quotient partial products. + let mut partial_product_check = check_partial_products_recursively( + builder, + "ient_values, + current_partial_products, + max_degree, + ); + // The first checks are of the form `q - n/d` which is a rational function not a polynomial. + // We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials. + denominator_values + .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); + }); + vanishing_partial_products_terms.extend(partial_product_check); + + // The quotient final product is the product of the last `final_num_prod` elements. + let quotient = + builder.mul_many_extension(¤t_partial_products[num_prods - final_num_prod..]); + vanishing_v_shift_terms.push(builder.mul_sub_extension(quotient, z_x, z_gz)); + } + + let vanishing_terms = [ + vanishing_z_1_terms, + vanishing_partial_products_terms, + vanishing_v_shift_terms, + constraint_terms, + ] + .concat(); + dbg!(&vanishing_terms); + + alphas + .iter() + .map(|&alpha| { + let alpha = builder.convert_to_ext(alpha); + let mut alpha = ReducingFactorTarget::new(alpha); + alpha.reduce(&vanishing_terms, builder) + }) + .collect() +} diff --git a/src/vars.rs b/src/vars.rs index 7e9b372f..17d51051 100644 --- a/src/vars.rs +++ b/src/vars.rs @@ -39,6 +39,12 @@ impl<'a, F: Field> EvaluationVarsBase<'a, F> { } } +impl<'a, const D: usize> EvaluationTargets<'a, D> { + pub fn remove_prefix(&mut self, prefix: &[bool]) { + self.local_constants = &self.local_constants[prefix.len()..]; + } +} + #[derive(Copy, Clone)] pub struct EvaluationTargets<'a, const D: usize> { pub(crate) local_constants: &'a [ExtensionTarget], diff --git a/src/verifier.rs b/src/verifier.rs index 64d4b371..e1d6d967 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -4,8 +4,9 @@ use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{eval_vanishing_poly, eval_zero_poly, reduce_with_powers}; +use crate::plonk_common::{eval_zero_poly, reduce_with_powers}; use crate::proof::Proof; +use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::EvaluationVars; pub(crate) fn verify, const D: usize>( @@ -39,7 +40,7 @@ pub(crate) fn verify, const D: usize>( }; let local_zs = &proof.openings.plonk_zs; let next_zs = &proof.openings.plonk_zs_right; - let s_sigmas = &proof.openings.plonk_s_sigmas; + let s_sigmas = &proof.openings.plonk_sigmas; let partial_products = &proof.openings.partial_products; // Evaluate the vanishing polynomial at our challenge point, zeta. From 139430c549497b03e2c2f5e48ce809f81cf75793 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 13 Jul 2021 09:15:16 +0200 Subject: [PATCH 04/21] Fixed GMiMC --- src/circuit_builder.rs | 2 +- src/circuit_data.rs | 12 ++++++-- src/gates/gate.rs | 3 ++ src/gates/gmimc.rs | 61 ++++++++++++++++++++++++++++++++++----- src/prover.rs | 11 ++++--- src/recursive_verifier.rs | 15 ++++++++-- src/util/marking.rs | 54 ++++++++++++++++++++++++++++++++++ src/util/mod.rs | 1 + src/vanishing_poly.rs | 10 +++++-- src/verifier.rs | 1 + 10 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 src/util/marking.rs diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 1d386b9d..fb0da833 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -45,7 +45,7 @@ pub struct CircuitBuilder, const D: usize> { copy_constraints: Vec<(Target, Target)>, /// Generators used to generate the witness. - generators: Vec>>, + pub generators: Vec>>, constants_to_targets: HashMap, targets_to_constants: HashMap, diff --git a/src/circuit_data.rs b/src/circuit_data.rs index e03a6977..786b7d78 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -11,6 +11,7 @@ use crate::polynomial::commitment::ListPolynomialCommitment; use crate::proof::{Hash, HashTarget, Proof}; use crate::prover::prove; use crate::target::Target; +use crate::util::marking::MarkedTargets; use crate::verifier::verify; use crate::witness::PartialWitness; @@ -77,7 +78,14 @@ pub struct CircuitData, const D: usize> { impl, const D: usize> CircuitData { pub fn prove(&self, inputs: PartialWitness) -> Proof { - prove(&self.prover_only, &self.common, inputs) + prove(&self.prover_only, &self.common, inputs, vec![]) + } + pub fn prove_marked( + &self, + inputs: PartialWitness, + marked: Vec, + ) -> Proof { + prove(&self.prover_only, &self.common, inputs, marked) } pub fn verify(&self, proof: Proof) -> Result<()> { @@ -99,7 +107,7 @@ pub struct ProverCircuitData, const D: usize> { impl, const D: usize> ProverCircuitData { pub fn prove(&self, inputs: PartialWitness) -> Proof { - prove(&self.prover_only, &self.common, inputs) + prove(&self.prover_only, &self.common, inputs, vec![]) } } diff --git a/src/gates/gate.rs b/src/gates/gate.rs index cce665f9..49b610ba 100644 --- a/src/gates/gate.rs +++ b/src/gates/gate.rs @@ -83,6 +83,9 @@ pub trait Gate, const D: usize>: 'static + Send + Sync { let filter = compute_filter_recursively(builder, prefix, vars.local_constants); vars.remove_prefix(prefix); self.eval_unfiltered_recursively(builder, vars) + .into_iter() + .map(|c| builder.mul_extension(filter, c)) + .collect() } fn generators( diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 9f617043..4f23a46e 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -129,16 +129,14 @@ impl, const D: usize, const R: usize> Gate for GMiMCGate< let mut constraints = Vec::with_capacity(self.num_constraints()); let swap = vars.local_wires[Self::WIRE_SWAP]; - let one_ext = builder.one_extension(); - let not_swap = builder.sub_extension(swap, one_ext); - constraints.push(builder.mul_extension(swap, not_swap)); + constraints.push(builder.mul_sub_extension(swap, swap, swap)); let old_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_OLD]; let new_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_NEW]; // computed_new_index_acc = 2 * old_index_acc + swap let two = builder.two(); - let double_old_index_acc = builder.scalar_mul_ext(two, old_index_acc); - let computed_new_index_acc = builder.add_extension(double_old_index_acc, swap); + let two = builder.convert_to_ext(two); + let computed_new_index_acc = builder.mul_add_extension(two, old_index_acc, swap); constraints.push(builder.sub_extension(computed_new_index_acc, new_index_acc)); let mut state = Vec::with_capacity(12); @@ -168,8 +166,10 @@ impl, const D: usize, const R: usize> Gate for GMiMCGate< let constant = builder.constant_extension(self.constants[r].into()); let cubing_input = builder.add_many_extension(&[state[active], addition_buffer, constant]); - let square = builder.mul_extension(cubing_input, cubing_input); - let f = builder.mul_extension(square, cubing_input); + let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)]; + constraints.push(builder.sub_extension(cubing_input, cubing_input_wire)); + let square = builder.mul_extension(cubing_input_wire, cubing_input_wire); + let f = builder.mul_extension(square, cubing_input_wire); addition_buffer = builder.add_extension(addition_buffer, f); state[active] = builder.sub_extension(state[active], f); } @@ -316,8 +316,10 @@ mod tests { use std::convert::TryInto; use std::sync::Arc; + use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; use crate::gates::gate_testing::test_low_degree; use crate::gates::gmimc::{GMiMCGate, W}; @@ -325,6 +327,8 @@ mod tests { use crate::gmimc::gmimc_permute_naive; use crate::permutation_argument::TargetPartition; use crate::target::Target; + use crate::vars::{EvaluationTargets, EvaluationVars}; + use crate::verifier::verify; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -399,4 +403,47 @@ mod tests { let gate = Gate::with_constants(constants); test_low_degree(gate) } + + #[test] + fn test_evals() { + type F = CrandallField; + type FF = QuarticCrandallField; + const R: usize = 101; + let config = CircuitConfig::large_config(); + let mut builder = CircuitBuilder::::new(config); + let mut pw = PartialWitness::::new(); + let constants = Arc::new([F::TWO; R]); + type Gate = GMiMCGate; + let gate = Gate::with_constants(constants); + + let wires = FF::rand_vec(Gate::end()); + let vars = EvaluationVars { + local_constants: &[], + local_wires: &wires, + }; + + let ev = gate.0.eval_unfiltered((vars)); + + let wires_t = builder.add_virtual_extension_targets(Gate::end()); + for i in 0..Gate::end() { + pw.set_extension_target(wires_t[i], wires[i]); + } + let vars_t = EvaluationTargets { + local_constants: &[], + local_wires: &wires_t, + }; + + let ev_t = gate.0.eval_unfiltered_recursively(&mut builder, vars_t); + + assert_eq!(ev.len(), ev_t.len()); + for (e, e_t) in ev.into_iter().zip(ev_t) { + let e_c = builder.constant_extension(e); + builder.route_extension(e_c, e_t); + } + + let data = builder.build(); + let proof = data.prove(pw); + + verify(proof, &data.verifier_only, &data.common).unwrap(); + } } diff --git a/src/prover.rs b/src/prover.rs index 8194551f..397b0fea 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -12,6 +12,7 @@ use crate::polynomial::commitment::ListPolynomialCommitment; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::Proof; use crate::timed; +use crate::util::marking::MarkedTargets; use crate::util::partial_products::partial_products; use crate::util::{log2_ceil, transpose}; use crate::vanishing_poly::eval_vanishing_poly_base; @@ -22,6 +23,7 @@ pub(crate) fn prove, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, inputs: PartialWitness, + marked: Vec, ) -> Proof { let fri_config = &common_data.config.fri_config; let config = &common_data.config; @@ -50,13 +52,10 @@ pub(crate) fn prove, const D: usize>( .unwrap(), // TODO: Change return value to `Result` and use `?` here. "to check copy constraints" ); - - if degree > 7 { - dbg!(witness.get_wire(8, 16)); - dbg!(witness.get_wire(8, 17)); - dbg!(witness.get_wire(8, 18)); - dbg!(witness.get_wire(8, 19)); + for m in marked { + m.display(&witness); } + let wires_values: Vec> = timed!( witness .wire_values diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 33912663..205ddb91 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -7,6 +7,7 @@ use crate::field::field::Field; use crate::gates::gate::{GateRef, PrefixedGate}; use crate::plonk_challenger::RecursiveChallenger; use crate::proof::{HashTarget, ProofTarget}; +use crate::util::marking::MarkedTargets; use crate::util::scaling::ReducingFactorTarget; use crate::vanishing_poly::eval_vanishing_poly_recursively; use crate::vars::EvaluationTargets; @@ -22,6 +23,7 @@ impl, const D: usize> CircuitBuilder { inner_config: &CircuitConfig, inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, + marked: &mut Vec, ) { assert!(self.config.num_wires >= MIN_WIRES); assert!(self.config.num_wires >= MIN_ROUTED_WIRES); @@ -71,8 +73,14 @@ impl, const D: usize> CircuitBuilder { &betas, &gammas, &alphas, + marked, ); + marked.push(MarkedTargets { + name: "vanishing polys".into(), + targets: Box::new(vanishing_polys_zeta[0].clone()), + }); + // let quotient_polys_zeta = &proof.openings.quotient_polys; // let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); // let z_h_zeta = self.sub_extension(zeta_pow_deg, one); @@ -318,6 +326,8 @@ mod tests { let config = CircuitConfig::large_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]); let data = builder.build(); ( data.prove(PartialWitness::new()), @@ -330,6 +340,7 @@ mod tests { let config = CircuitConfig::large_config(); 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); set_proof_target(&proof, &pt, &mut pw); @@ -338,11 +349,11 @@ mod tests { }; pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); - builder.add_recursive_verifier(pt, &config, &inner_data, &cd); + builder.add_recursive_verifier(pt, &config, &inner_data, &cd, &mut marked); dbg!(builder.num_gates()); let data = builder.build(); - let recursive_proof = data.prove(pw); + let recursive_proof = data.prove_marked(pw, marked); verify(recursive_proof, &data.verifier_only, &data.common).unwrap(); } diff --git a/src/util/marking.rs b/src/util/marking.rs new file mode 100644 index 00000000..e4a13499 --- /dev/null +++ b/src/util/marking.rs @@ -0,0 +1,54 @@ +use std::convert::TryInto; + +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::field::Field; +use crate::proof::HashTarget; +use crate::target::Target; +use crate::witness::{PartialWitness, Witness}; + +pub trait Markable { + fn targets(&self) -> Vec; +} + +impl Markable for Target { + fn targets(&self) -> Vec { + vec![*self] + } +} + +impl Markable for ExtensionTarget { + fn targets(&self) -> Vec { + self.0.try_into().unwrap() + } +} + +impl Markable for HashTarget { + fn targets(&self) -> Vec { + self.elements.try_into().unwrap() + } +} + +impl Markable for Vec { + fn targets(&self) -> Vec { + self.iter().flat_map(|m| m.targets()).collect() + } +} + +pub struct MarkedTargets { + pub targets: Box, + pub name: String, +} + +impl MarkedTargets { + pub fn display(&self, wit: &Witness) { + let targets = self.targets.targets(); + println!("Values for {}:", self.name); + for &t in &targets { + match t { + Target::Wire(w) => println!("{}", wit.get_wire(w.gate, w.input)), + _ => println!("Not a wire."), + } + } + println!("End of values for {}", self.name); + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs index 85440d70..6fd0e562 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,4 @@ +pub mod marking; pub mod partial_products; pub mod scaling; pub(crate) mod timing; diff --git a/src/vanishing_poly.rs b/src/vanishing_poly.rs index a5f63ac2..d1531051 100644 --- a/src/vanishing_poly.rs +++ b/src/vanishing_poly.rs @@ -7,6 +7,7 @@ use crate::gates::gate::{Gate, GateRef, PrefixedGate}; use crate::plonk_common; use crate::plonk_common::{eval_l_1_recursively, ZeroPolyOnCoset}; use crate::target::Target; +use crate::util::marking::MarkedTargets; use crate::util::partial_products::{check_partial_products, check_partial_products_recursively}; use crate::util::scaling::ReducingFactorTarget; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; @@ -94,7 +95,6 @@ pub(crate) fn eval_vanishing_poly, const D: usize>( constraint_terms, ] .concat(); - dbg!(&vanishing_terms); let alphas = &alphas.iter().map(|&a| a.into()).collect::>(); plonk_common::reduce_with_powers_multi(&vanishing_terms, alphas) @@ -233,6 +233,7 @@ pub fn evaluate_gate_constraints_recursively, const D: usize>( gates: &[PrefixedGate], num_gate_constraints: usize, vars: EvaluationTargets, + marked: &mut Vec, ) -> Vec> { let mut constraints = vec![builder.zero_extension(); num_gate_constraints]; for gate in gates { @@ -240,6 +241,10 @@ pub fn evaluate_gate_constraints_recursively, const D: usize>( .gate .0 .eval_filtered_recursively(builder, vars, &gate.prefix); + // marked.push(MarkedTargets { + // name: gate.gate.0.id(), + // targets: Box::new(gate_constraints.clone()), + // }); for (i, c) in gate_constraints.into_iter().enumerate() { constraints[i] = builder.add_extension(constraints[i], c); } @@ -263,6 +268,7 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( betas: &[Target], gammas: &[Target], alphas: &[Target], + marked: &mut Vec, ) -> Vec> { let max_degree = common_data.quotient_degree_factor; let (num_prods, final_num_prod) = common_data.num_partial_products; @@ -272,6 +278,7 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( &common_data.gates, common_data.num_gate_constraints, vars, + marked, ); // The L_1(x) (Z(x) - 1) vanishing terms. @@ -343,7 +350,6 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( constraint_terms, ] .concat(); - dbg!(&vanishing_terms); alphas .iter() diff --git a/src/verifier.rs b/src/verifier.rs index e1d6d967..6da5a2e2 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -56,6 +56,7 @@ 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; From c99d7f48fd241907b9567585e99a14d2356993fe Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 13 Jul 2021 09:44:35 +0200 Subject: [PATCH 05/21] Add Merkle tree test --- src/merkle_proofs.rs | 59 ++++++++++++++++++++++++++++++++++ src/recursive_verifier.rs | 66 +++++++++++++++++++-------------------- 2 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index b098657c..002a0d5a 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -135,3 +135,62 @@ impl, const D: usize> CircuitBuilder { } } } + +#[cfg(test)] +mod tests { + use anyhow::Result; + use rand::{thread_rng, Rng}; + + use super::*; + use crate::circuit_data::CircuitConfig; + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::merkle_proofs::verify_merkle_proof; + use crate::merkle_tree::MerkleTree; + use crate::verifier::verify; + use crate::witness::PartialWitness; + + fn random_data(n: usize, k: usize) -> Vec> { + (0..n).map(|_| F::rand_vec(k)).collect() + } + + #[test] + fn test_merkle_trees() -> Result<()> { + type F = CrandallField; + type FF = QuarticCrandallField; + let config = CircuitConfig::large_config(); + let mut builder = CircuitBuilder::::new(config); + let mut pw = PartialWitness::new(); + + let log_n = 8; + let n = 1 << log_n; + let leaves = random_data::(n, 7); + let tree = MerkleTree::new(leaves.clone(), false); + let i: usize = thread_rng().gen_range(0, n); + let proof = tree.prove(i); + + let proof_t = MerkleProofTarget { + siblings: builder.add_virtual_hashes(proof.siblings.len()), + }; + for i in 0..proof.siblings.len() { + pw.set_hash_target(proof_t.siblings[i], proof.siblings[i]); + } + + let root_t = builder.add_virtual_hash(); + pw.set_hash_target(root_t, tree.root); + + let i_c = builder.constant(F::from_canonical_usize(i)); + + let data = builder.add_virtual_targets(tree.leaves[i].len()); + for j in 0..data.len() { + pw.set_target(data[j], tree.leaves[i][j]); + } + + builder.verify_merkle_proof(data, i_c, root_t, &proof_t); + + let data = builder.build(); + let proof = data.prove(pw); + + verify(proof, &data.verifier_only, &data.common) + } +} diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 205ddb91..7a35c728 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -81,39 +81,39 @@ impl, const D: usize> CircuitBuilder { targets: Box::new(vanishing_polys_zeta[0].clone()), }); - // let quotient_polys_zeta = &proof.openings.quotient_polys; - // let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); - // let z_h_zeta = self.sub_extension(zeta_pow_deg, one); - // for (i, chunk) in quotient_polys_zeta - // .chunks(inner_common_data.quotient_degree_factor) - // .enumerate() - // { - // 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); - // } - // - // let evaluations = proof.openings.clone(); - // - // let merkle_roots = &[ - // inner_verifier_data.constants_sigmas_root, - // proof.wires_root, - // proof.plonk_zs_root, - // proof.quotient_polys_root, - // ]; - // - // proof.opening_proof.verify( - // zeta, - // &evaluations, - // merkle_roots, - // &mut challenger, - // inner_common_data, - // self, - // ); - // dbg!(self.num_gates()); - // dbg!(self.generators.len()); + let quotient_polys_zeta = &proof.openings.quotient_polys; + let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); + let z_h_zeta = self.sub_extension(zeta_pow_deg, one); + for (i, chunk) in quotient_polys_zeta + .chunks(inner_common_data.quotient_degree_factor) + .enumerate() + { + 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); + } + + let evaluations = proof.openings.clone(); + + let merkle_roots = &[ + inner_verifier_data.constants_sigmas_root, + proof.wires_root, + proof.plonk_zs_root, + proof.quotient_polys_root, + ]; + + proof.opening_proof.verify( + zeta, + &evaluations, + merkle_roots, + &mut challenger, + inner_common_data, + self, + ); + dbg!(self.num_gates()); + dbg!(self.generators.len()); } } From 5c2c01b1abe33ff4e11db60e576a05f624532ed3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 13 Jul 2021 15:20:14 +0200 Subject: [PATCH 06/21] 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; From c3d53392c423be083272dfffdadb5ab79d107155 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 14 Jul 2021 08:14:00 +0200 Subject: [PATCH 07/21] Problem in permutation argument --- src/circuit_builder.rs | 4 +- src/circuit_data.rs | 1 + src/gadgets/arithmetic_extension.rs | 2 +- src/polynomial/commitment.rs | 8 +- src/prover.rs | 174 +++++++++++++++++++++++++++- src/recursive_verifier.rs | 1 + src/vanishing_poly.rs | 104 ++++++++++++++++- 7 files changed, 284 insertions(+), 10 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index fb0da833..1e0bfaef 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -296,7 +296,7 @@ impl, const D: usize> CircuitBuilder { } } - fn blind_and_pad(&mut self) { + pub fn blind_and_pad(&mut self) { let (regular_poly_openings, z_openings) = self.blinding_counts(); info!( "Adding {} blinding terms for witness polynomials, and {}*2 for Z polynomials", @@ -349,7 +349,7 @@ impl, const D: usize> CircuitBuilder { } } - fn constant_polys( + pub fn constant_polys( &self, gates: &[PrefixedGate], num_constants: usize, diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 786b7d78..91afdd23 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -8,6 +8,7 @@ use crate::fri::FriConfig; use crate::gates::gate::{GateInstance, PrefixedGate}; use crate::generator::WitnessGenerator; use crate::polynomial::commitment::ListPolynomialCommitment; +use crate::polynomial::polynomial::PolynomialValues; use crate::proof::{Hash, HashTarget, Proof}; use crate::prover::prove; use crate::target::Target; diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 57968a23..49748040 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -459,7 +459,7 @@ mod tests { let config = CircuitConfig::large_config(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config.clone()); let x = FF::rand(); let y = FF::rand(); diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index bb6f0e4e..d27718ae 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -20,6 +20,7 @@ use crate::util::{log2_ceil, log2_strict, reverse_bits, reverse_index_bits_in_pl pub const SALT_SIZE: usize = 2; pub struct ListPolynomialCommitment { + pub original_values: Vec>, // TODO: Remove when debugging is done. pub polynomials: Vec>, pub merkle_tree: MerkleTree, pub degree: usize, @@ -41,7 +42,7 @@ impl ListPolynomialCommitment { "to compute LDE" ); - Self::new_from_data(polynomials, lde_values, degree, rate_bits, blinding) + Self::new_from_data(values, polynomials, lde_values, degree, rate_bits, blinding) } /// Creates a list polynomial commitment for the polynomials `polynomials`. @@ -51,15 +52,17 @@ impl ListPolynomialCommitment { blinding: bool, ) -> Self { let degree = polynomials[0].len(); + let values = polynomials.iter().map(|p| p.clone().fft()).collect(); let lde_values = timed!( Self::lde_values(&polynomials, rate_bits, blinding), "to compute LDE" ); - Self::new_from_data(polynomials, lde_values, degree, rate_bits, blinding) + Self::new_from_data(values, polynomials, lde_values, degree, rate_bits, blinding) } fn new_from_data( + values: Vec>, polynomials: Vec>, lde_values: Vec>, degree: usize, @@ -71,6 +74,7 @@ impl ListPolynomialCommitment { let merkle_tree = timed!(MerkleTree::new(leaves, false), "to build Merkle tree"); Self { + original_values: values, polynomials, merkle_tree, degree, diff --git a/src/prover.rs b/src/prover.rs index 23c07514..6d494c05 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::time::Instant; use log::info; @@ -5,6 +6,7 @@ use rayon::prelude::*; use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; use crate::field::extension_field::Extendable; +use crate::field::field::Field; use crate::generator::generate_partial_witness; use crate::plonk_challenger::Challenger; use crate::plonk_common::{PlonkPolynomials, ZeroPolyOnCoset}; @@ -15,8 +17,10 @@ use crate::timed; use crate::util::marking::MarkedTargets; use crate::util::partial_products::partial_products; use crate::util::{log2_ceil, transpose}; -use crate::vanishing_poly::eval_vanishing_poly_base; -use crate::vars::EvaluationVarsBase; +use crate::vanishing_poly::{ + eval_vanishing_poly_base, evaluate_gate_constraints, evaluate_gate_constraints_base, yoba, +}; +use crate::vars::{EvaluationVars, EvaluationVarsBase}; use crate::witness::{PartialWitness, Witness}; pub(crate) fn prove, const D: usize>( @@ -116,6 +120,169 @@ pub(crate) fn prove, const D: usize>( let alphas = challenger.get_n_challenges(num_challenges); + { + let get_at_index = |comm: &ListPolynomialCommitment, i: usize| -> Vec { + comm.original_values + .iter() + .map(|v| v.values[i]) + .collect::>() + }; + let mut nums = HashMap::::new(); + let mut dens = HashMap::::new(); + let points = F::two_adic_subgroup(common_data.degree_bits); + for i in 0..degree { + let x = points[i]; + let local_constants_sigmas = get_at_index(&prover_data.constants_sigmas_commitment, i); + let local_constants = &local_constants_sigmas[common_data.constants_range()]; + let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()]; + let local_wires = get_at_index(&wires_commitment, i); + let vars = EvaluationVarsBase { + local_constants, + local_wires: &local_wires, + }; + let numerator_values = (0..common_data.config.num_routed_wires).for_each(|j| { + let wire_value = vars.local_wires[j]; + let k_i = common_data.k_is[j]; + let s_id = k_i * x; + *nums + .entry(wire_value + betas[0] * s_id + gammas[0]) + .or_default() += 1; + }); + let denominator_values = (0..common_data.config.num_routed_wires).for_each(|j| { + let wire_value = vars.local_wires[j]; + let s_sigma = s_sigmas[j]; + *dens + .entry(wire_value + betas[0] * s_sigma + gammas[0]) + .or_default() += 1; + }); + } + println!("yo"); + for (k, v) in nums.iter() { + if let Some(w) = dens.get(&k) { + if *v != *w { + println!("Bad: {} {} {}", *k, *v, *w); + } + } else { + println!("Bad: {} {}", *k, *v); + } + } + println!("ya"); + for (k, v) in dens.iter() { + if let Some(w) = nums.get(&k) { + if *v != *w { + println!("Bad: {} {} {}", *k, *v, *w); + } + } else { + println!("Bad: {} {}", *k, *v); + } + } + println!("yu"); + + let mut bam = F::ONE; + for (k, v) in nums.iter() { + bam *= k.exp(*v as u64); + } + dbg!(bam); + let mut boom = F::ONE; + for (k, v) in dens.iter() { + boom *= k.exp(*v as u64); + } + dbg!(boom); + } + { + let get_at_index = |comm: &ListPolynomialCommitment, i: usize| -> Vec { + comm.original_values + .iter() + .map(|v| v.values[i]) + .collect::>() + }; + let mut nums = vec![F::ONE; common_data.config.num_challenges]; + let mut dens = vec![F::ONE; common_data.config.num_challenges]; + let points = F::two_adic_subgroup(common_data.degree_bits); + for i in 0..degree { + let x = points[i]; + let local_constants_sigmas = get_at_index(&prover_data.constants_sigmas_commitment, i); + let local_constants = &local_constants_sigmas[common_data.constants_range()]; + let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()]; + let local_wires = get_at_index(&wires_commitment, i); + let vars = EvaluationVarsBase { + local_constants, + local_wires: &local_wires, + }; + for ii in 0..common_data.config.num_challenges { + let numerator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let k_i = common_data.k_is[j]; + let s_id = k_i * x; + wire_value + betas[ii] * s_id + gammas[ii] + }) + .collect::>(); + let denominator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let s_sigma = s_sigmas[j]; + wire_value + betas[ii] * s_sigma + gammas[ii] + }) + .collect::>(); + + nums[ii] *= numerator_values.into_iter().product(); + dens[ii] *= denominator_values.into_iter().product(); + } + } + dbg!(nums, dens); + } + { + let get_at_index = |comm: &ListPolynomialCommitment, i: usize| -> Vec { + comm.original_values + .iter() + .map(|v| v.values[i]) + .collect::>() + }; + let points = F::two_adic_subgroup(common_data.degree_bits); + for i in 0..degree { + let x = points[i]; + let i_next = (i + 1) % degree; + let local_constants_sigmas = get_at_index(&prover_data.constants_sigmas_commitment, i); + let local_constants = &local_constants_sigmas[common_data.constants_range()]; + let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()]; + let local_wires = get_at_index(&wires_commitment, i); + let local_zs_partial_products = get_at_index(&zs_partial_products_commitment, i); + let local_zs = &local_zs_partial_products[common_data.zs_range()]; + let next_zs = + &get_at_index(&zs_partial_products_commitment, i_next)[common_data.zs_range()]; + let partial_products = &local_zs_partial_products[common_data.partial_products_range()]; + + debug_assert_eq!(local_wires.len(), common_data.config.num_wires); + debug_assert_eq!(local_zs.len(), num_challenges); + + let vars = EvaluationVarsBase { + local_constants, + local_wires: &local_wires, + }; + let mut quotient_values = yoba( + common_data, + i, + x, + vars, + local_zs, + next_zs, + partial_products, + s_sigmas, + &betas, + &gammas, + &alphas, + ); + assert!( + quotient_values.iter().all(|yy| yy.is_zero()), + "{}-th gate ({}) constraints not satisfied.\n {:?}", + i, + prover_data.gate_instances[i].gate_type.0.id(), + quotient_values + ); + } + } + let quotient_polys = timed!( compute_quotient_polys( common_data, @@ -136,8 +303,7 @@ pub(crate) fn prove, const D: usize>( .flat_map(|mut quotient_poly| { quotient_poly.trim(); quotient_poly.pad(quotient_degree).expect( - "The quotient polynomial doesn't have the right degree. \ - This may be because the `Z`s polynomials are still too high degree.", + "Quotient has failed, the vanishing polynomial is not divisible by `Z_H", ); // Split t into degree-n chunks. quotient_poly.chunks(degree) diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 2bc77e07..46a52cd3 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -321,6 +321,7 @@ mod tests { #[test] fn test_recursive_verifier() { + env_logger::init(); type F = CrandallField; type FF = QuarticCrandallField; const D: usize = 4; diff --git a/src/vanishing_poly.rs b/src/vanishing_poly.rs index d1531051..6c336593 100644 --- a/src/vanishing_poly.rs +++ b/src/vanishing_poly.rs @@ -5,7 +5,7 @@ use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::gates::gate::{Gate, GateRef, PrefixedGate}; use crate::plonk_common; -use crate::plonk_common::{eval_l_1_recursively, ZeroPolyOnCoset}; +use crate::plonk_common::{eval_l_1, eval_l_1_recursively, ZeroPolyOnCoset}; use crate::target::Target; use crate::util::marking::MarkedTargets; use crate::util::partial_products::{check_partial_products, check_partial_products_recursively}; @@ -185,6 +185,108 @@ pub(crate) fn eval_vanishing_poly_base, const D: usize>( plonk_common::reduce_with_powers_multi(&vanishing_terms, alphas) } +pub(crate) fn yoba, const D: usize>( + common_data: &CommonCircuitData, + index: usize, + x: F, + vars: EvaluationVarsBase, + local_zs: &[F], + next_zs: &[F], + partial_products: &[F], + s_sigmas: &[F], + betas: &[F], + gammas: &[F], + alphas: &[F], +) -> Vec { + let max_degree = common_data.quotient_degree_factor; + let (num_prods, final_num_prod) = common_data.num_partial_products; + + let constraint_terms = + evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars); + + // The L_1(x) (Z(x) - 1) vanishing terms. + let mut vanishing_z_1_terms = Vec::new(); + // The terms checking the partial products. + let mut vanishing_partial_products_terms = Vec::new(); + // The Z(x) f'(x) - g'(x) Z(g x) terms. + let mut vanishing_v_shift_terms = Vec::new(); + + for i in 0..common_data.config.num_challenges { + let z_x = local_zs[i]; + let z_gz = next_zs[i]; + vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::ONE)); + + let numerator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let k_i = common_data.k_is[j]; + let s_id = k_i * x; + wire_value + betas[i] * s_id + gammas[i] + }) + .collect::>(); + let denominator_values = (0..common_data.config.num_routed_wires) + .map(|j| { + let wire_value = vars.local_wires[j]; + let s_sigma = s_sigmas[j]; + wire_value + betas[i] * s_sigma + gammas[i] + }) + .collect::>(); + let quotient_values = (0..common_data.config.num_routed_wires) + .map(|j| numerator_values[j] / denominator_values[j]) + .collect::>(); + + // The partial products considered for this iteration of `i`. + let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; + // Check the numerator partial products. + let mut partial_product_check = + check_partial_products("ient_values, current_partial_products, max_degree); + // The first checks are of the form `q - n/d` which is a rational function not a polynomial. + // We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials. + denominator_values + .chunks(max_degree) + .zip(partial_product_check.iter_mut()) + .for_each(|(d, q)| { + *q *= d.iter().copied().product(); + }); + vanishing_partial_products_terms.extend(partial_product_check); + + // The quotient final product is the product of the last `final_num_prod` elements. + let quotient: F = current_partial_products[num_prods - final_num_prod..] + .iter() + .copied() + .product(); + assert_eq!( + quotient, + numerator_values.iter().copied().product::() + / denominator_values.iter().copied().product::() + ); + vanishing_v_shift_terms.push(quotient * z_x - z_gz); + } + + if vanishing_z_1_terms.iter().any(|x| !x.is_zero()) { + dbg!(&vanishing_z_1_terms); + } + if vanishing_partial_products_terms + .iter() + .any(|x| !x.is_zero()) + { + dbg!(&vanishing_partial_products_terms); + } + if vanishing_v_shift_terms.iter().any(|x| !x.is_zero()) { + dbg!(&vanishing_v_shift_terms); + } + if constraint_terms.iter().any(|x| !x.is_zero()) { + dbg!(&constraint_terms); + } + [ + vanishing_z_1_terms, + vanishing_partial_products_terms, + vanishing_v_shift_terms, + constraint_terms, + ] + .concat() +} + /// Evaluates all gate constraints. /// /// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not From dcdbb6be330921759d12d1f14c53f68754b8d61a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 14 Jul 2021 18:44:58 +0200 Subject: [PATCH 08/21] Check copy constraints in PartialWitness --- src/prover.rs | 176 ++----------------------------------------------- src/witness.rs | 73 ++++++++++---------- 2 files changed, 45 insertions(+), 204 deletions(-) diff --git a/src/prover.rs b/src/prover.rs index 6d494c05..aa0ecf30 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -45,6 +45,13 @@ pub(crate) fn prove, const D: usize>( "to generate witness" ); + timed!( + partial_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" + ); + let witness = timed!( partial_witness.full_witness(degree, num_wires), "to compute full witness" @@ -53,12 +60,6 @@ pub(crate) fn prove, const D: usize>( 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" - ); let wires_values: Vec> = timed!( witness @@ -120,169 +121,6 @@ pub(crate) fn prove, const D: usize>( let alphas = challenger.get_n_challenges(num_challenges); - { - let get_at_index = |comm: &ListPolynomialCommitment, i: usize| -> Vec { - comm.original_values - .iter() - .map(|v| v.values[i]) - .collect::>() - }; - let mut nums = HashMap::::new(); - let mut dens = HashMap::::new(); - let points = F::two_adic_subgroup(common_data.degree_bits); - for i in 0..degree { - let x = points[i]; - let local_constants_sigmas = get_at_index(&prover_data.constants_sigmas_commitment, i); - let local_constants = &local_constants_sigmas[common_data.constants_range()]; - let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()]; - let local_wires = get_at_index(&wires_commitment, i); - let vars = EvaluationVarsBase { - local_constants, - local_wires: &local_wires, - }; - let numerator_values = (0..common_data.config.num_routed_wires).for_each(|j| { - let wire_value = vars.local_wires[j]; - let k_i = common_data.k_is[j]; - let s_id = k_i * x; - *nums - .entry(wire_value + betas[0] * s_id + gammas[0]) - .or_default() += 1; - }); - let denominator_values = (0..common_data.config.num_routed_wires).for_each(|j| { - let wire_value = vars.local_wires[j]; - let s_sigma = s_sigmas[j]; - *dens - .entry(wire_value + betas[0] * s_sigma + gammas[0]) - .or_default() += 1; - }); - } - println!("yo"); - for (k, v) in nums.iter() { - if let Some(w) = dens.get(&k) { - if *v != *w { - println!("Bad: {} {} {}", *k, *v, *w); - } - } else { - println!("Bad: {} {}", *k, *v); - } - } - println!("ya"); - for (k, v) in dens.iter() { - if let Some(w) = nums.get(&k) { - if *v != *w { - println!("Bad: {} {} {}", *k, *v, *w); - } - } else { - println!("Bad: {} {}", *k, *v); - } - } - println!("yu"); - - let mut bam = F::ONE; - for (k, v) in nums.iter() { - bam *= k.exp(*v as u64); - } - dbg!(bam); - let mut boom = F::ONE; - for (k, v) in dens.iter() { - boom *= k.exp(*v as u64); - } - dbg!(boom); - } - { - let get_at_index = |comm: &ListPolynomialCommitment, i: usize| -> Vec { - comm.original_values - .iter() - .map(|v| v.values[i]) - .collect::>() - }; - let mut nums = vec![F::ONE; common_data.config.num_challenges]; - let mut dens = vec![F::ONE; common_data.config.num_challenges]; - let points = F::two_adic_subgroup(common_data.degree_bits); - for i in 0..degree { - let x = points[i]; - let local_constants_sigmas = get_at_index(&prover_data.constants_sigmas_commitment, i); - let local_constants = &local_constants_sigmas[common_data.constants_range()]; - let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()]; - let local_wires = get_at_index(&wires_commitment, i); - let vars = EvaluationVarsBase { - local_constants, - local_wires: &local_wires, - }; - for ii in 0..common_data.config.num_challenges { - let numerator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let k_i = common_data.k_is[j]; - let s_id = k_i * x; - wire_value + betas[ii] * s_id + gammas[ii] - }) - .collect::>(); - let denominator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let s_sigma = s_sigmas[j]; - wire_value + betas[ii] * s_sigma + gammas[ii] - }) - .collect::>(); - - nums[ii] *= numerator_values.into_iter().product(); - dens[ii] *= denominator_values.into_iter().product(); - } - } - dbg!(nums, dens); - } - { - let get_at_index = |comm: &ListPolynomialCommitment, i: usize| -> Vec { - comm.original_values - .iter() - .map(|v| v.values[i]) - .collect::>() - }; - let points = F::two_adic_subgroup(common_data.degree_bits); - for i in 0..degree { - let x = points[i]; - let i_next = (i + 1) % degree; - let local_constants_sigmas = get_at_index(&prover_data.constants_sigmas_commitment, i); - let local_constants = &local_constants_sigmas[common_data.constants_range()]; - let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()]; - let local_wires = get_at_index(&wires_commitment, i); - let local_zs_partial_products = get_at_index(&zs_partial_products_commitment, i); - let local_zs = &local_zs_partial_products[common_data.zs_range()]; - let next_zs = - &get_at_index(&zs_partial_products_commitment, i_next)[common_data.zs_range()]; - let partial_products = &local_zs_partial_products[common_data.partial_products_range()]; - - debug_assert_eq!(local_wires.len(), common_data.config.num_wires); - debug_assert_eq!(local_zs.len(), num_challenges); - - let vars = EvaluationVarsBase { - local_constants, - local_wires: &local_wires, - }; - let mut quotient_values = yoba( - common_data, - i, - x, - vars, - local_zs, - next_zs, - partial_products, - s_sigmas, - &betas, - &gammas, - &alphas, - ); - assert!( - quotient_values.iter().all(|yy| yy.is_zero()), - "{}-th gate ({}) constraints not satisfied.\n {:?}", - i, - prover_data.gate_instances[i].gate_type.0.id(), - quotient_values - ); - } - } - let quotient_polys = timed!( compute_quotient_polys( common_data, diff --git a/src/witness.rs b/src/witness.rs index c8705803..0f930971 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -20,41 +20,6 @@ impl Witness { pub fn get_wire(&self, gate: usize, input: usize) -> F { self.wire_values[input][gate] } - - /// Checks that the copy constraints are satisfied in the witness. - pub fn check_copy_constraints( - &self, - copy_constraints: &[(Target, Target)], - gate_instances: &[GateInstance], - ) -> Result<()> - where - F: Extendable, - { - for &(a, b) in copy_constraints { - // TODO: Take care of public inputs once they land, and virtual targets. - if let ( - Target::Wire(Wire { - gate: a_gate, - input: a_input, - }), - Target::Wire(Wire { - gate: b_gate, - input: b_input, - }), - ) = (a, b) - { - let va = self.get_wire(a_gate, a_input); - let vb = self.get_wire(b_gate, b_input); - ensure!( - va == vb, - "Copy constraint between wire {} of gate #{} (`{}`) and wire {} of gate #{} (`{}`) is not satisfied. \ - Got values of {} and {} respectively.", - a_input, a_gate, gate_instances[a_gate].gate_type.0.id(), b_input, b_gate, - gate_instances[b_gate].gate_type.0.id(), va, vb); - } - } - Ok(()) - } } #[derive(Clone, Debug)] @@ -200,6 +165,44 @@ impl PartialWitness { }); Witness { wire_values } } + + /// Checks that the copy constraints are satisfied in the witness. + pub fn check_copy_constraints( + &self, + copy_constraints: &[(Target, Target)], + gate_instances: &[GateInstance], + ) -> Result<()> + where + F: Extendable, + { + for &(a, b) in copy_constraints { + // TODO: Take care of public inputs once they land. + let va = self.try_get_target(a).unwrap_or(F::ZERO); + let vb = self.try_get_target(b).unwrap_or(F::ZERO); + let desc = |t: Target| -> String { + match t { + Target::Wire(Wire { gate, input }) => format!( + "wire {} of gate #{} (`{}`)", + input, + gate, + gate_instances[gate].gate_type.0.id() + ), + Target::PublicInput { index } => format!("{}-th public input", index), + Target::VirtualTarget { index } => format!("{}-th virtual target", index), + } + }; + ensure!( + va == vb, + "Copy constraint between {} and {} is not satisfied. \ + Got values of {} and {} respectively.", + desc(a), + desc(b), + va, + vb + ); + } + Ok(()) + } } impl Default for PartialWitness { From 7793b5a956ba78e7c38a7392bcef1f33745df4b0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 14 Jul 2021 20:54:30 +0200 Subject: [PATCH 09/21] Identify problem in GMiMc --- src/circuit_builder.rs | 73 ++++++++++++++- src/circuit_data.rs | 15 ++-- src/copy_constraint.rs | 21 +++++ src/fri/prover.rs | 4 + src/fri/recursive_verifier.rs | 22 ++++- src/lib.rs | 1 + src/merkle_proofs.rs | 162 ++++++++++++++++------------------ src/prover.rs | 9 +- src/recursive_verifier.rs | 17 +++- src/util/marking.rs | 13 ++- src/witness.rs | 16 ++-- 11 files changed, 227 insertions(+), 126 deletions(-) create mode 100644 src/copy_constraint.rs diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 1e0bfaef..a2c6d935 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; use std::convert::TryInto; +use std::sync::Arc; use std::time::Instant; use log::info; @@ -8,6 +9,7 @@ use crate::circuit_data::{ CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData, VerifierCircuitData, VerifierOnlyCircuitData, }; +use crate::copy_constraint::CopyConstraint; use crate::field::cosets::get_unique_coset_shifts; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; @@ -23,6 +25,7 @@ use crate::polynomial::commitment::ListPolynomialCommitment; use crate::polynomial::polynomial::PolynomialValues; use crate::proof::HashTarget; use crate::target::Target; +use crate::util::marking::{Markable, MarkedTargets}; use crate::util::partial_products::num_partial_products; use crate::util::{log2_ceil, log2_strict, transpose, transpose_poly_values}; use crate::wire::Wire; @@ -42,7 +45,11 @@ pub struct CircuitBuilder, const D: usize> { /// The next available index for a `VirtualTarget`. pub virtual_target_index: usize, - copy_constraints: Vec<(Target, Target)>, + copy_constraints: Vec, + + context: String, + + pub marked_targets: Vec, /// Generators used to generate the witness. pub generators: Vec>>, @@ -60,6 +67,8 @@ impl, const D: usize> CircuitBuilder { public_input_index: 0, virtual_target_index: 0, copy_constraints: Vec::new(), + context: String::new(), + marked_targets: Vec::new(), generators: Vec::new(), constants_to_targets: HashMap::new(), targets_to_constants: HashMap::new(), @@ -158,12 +167,29 @@ impl, const D: usize> CircuitBuilder { self.assert_equal(src, dst); } + /// Same as `route` with a named copy constraint. + pub fn named_route(&mut self, src: Target, dst: Target, name: String) { + self.generate_copy(src, dst); + self.named_assert_equal(src, dst, name); + } + pub fn route_extension(&mut self, src: ExtensionTarget, dst: ExtensionTarget) { for i in 0..D { self.route(src.0[i], dst.0[i]); } } + pub fn named_route_extension( + &mut self, + src: ExtensionTarget, + dst: ExtensionTarget, + name: String, + ) { + for i in 0..D { + self.named_route(src.0[i], dst.0[i], format!("{}: limb {}", name, i)); + } + } + /// Adds a generator which will copy `src` to `dst`. pub fn generate_copy(&mut self, src: Target, dst: Target) { self.add_generator(CopyGenerator { src, dst }); @@ -180,7 +206,24 @@ impl, const D: usize> CircuitBuilder { y.is_routable(&self.config), "Tried to route a wire that isn't routable" ); - self.copy_constraints.push((x, y)); + self.copy_constraints + .push(CopyConstraint::new((x, y), self.context.clone())); + } + + /// Same as `assert_equal` for a named copy constraint. + pub fn named_assert_equal(&mut self, x: Target, y: Target, name: String) { + assert!( + x.is_routable(&self.config), + "Tried to route a wire that isn't routable" + ); + assert!( + y.is_routable(&self.config), + "Tried to route a wire that isn't routable" + ); + self.copy_constraints.push(CopyConstraint::new( + (x, y), + format!("{}: {}", self.context.clone(), name), + )); } pub fn assert_zero(&mut self, x: Target) { @@ -194,6 +237,18 @@ impl, const D: usize> CircuitBuilder { } } + pub fn named_assert_equal_extension( + &mut self, + x: ExtensionTarget, + y: ExtensionTarget, + name: String, + ) { + for i in 0..D { + self.assert_equal(x.0[i], y.0[i]); + self.named_assert_equal(x.0[i], y.0[i], format!("{}: limb {}", name, i)); + } + } + pub fn add_generators(&mut self, generators: Vec>>) { self.generators.extend(generators); } @@ -249,6 +304,17 @@ impl, const D: usize> CircuitBuilder { self.targets_to_constants.get(&target).cloned() } + pub fn set_context(&mut self, new_context: &str) { + self.context = new_context.to_string(); + } + + pub fn add_marked(&mut self, targets: Arc, name: &str) { + self.marked_targets.push(MarkedTargets { + targets, + name: name.to_string(), + }) + } + /// The number of polynomial values that will be revealed per opening, both for the "regular" /// polynomials and for the Z polynomials. Because calculating these values involves a recursive /// dependence (the amount of blinding depends on the degree, which depends on the blinding), @@ -402,7 +468,7 @@ impl, const D: usize> CircuitBuilder { target_partition.add(Target::VirtualTarget { index }); } - for &(a, b) in &self.copy_constraints { + for &CopyConstraint { pair: (a, b), .. } in &self.copy_constraints { target_partition.merge(a, b); } @@ -457,6 +523,7 @@ impl, const D: usize> CircuitBuilder { subgroup, copy_constraints: self.copy_constraints, gate_instances: self.gate_instances, + marked_targets: self.marked_targets, }; // The HashSet of gates will have a non-deterministic order. When converting to a Vec, we diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 91afdd23..e2df2755 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -2,6 +2,7 @@ use std::ops::{Range, RangeFrom}; use anyhow::Result; +use crate::copy_constraint::CopyConstraint; use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::fri::FriConfig; @@ -79,14 +80,7 @@ pub struct CircuitData, const D: usize> { impl, const D: usize> CircuitData { pub fn prove(&self, inputs: PartialWitness) -> Proof { - prove(&self.prover_only, &self.common, inputs, vec![]) - } - pub fn prove_marked( - &self, - inputs: PartialWitness, - marked: Vec, - ) -> Proof { - prove(&self.prover_only, &self.common, inputs, marked) + prove(&self.prover_only, &self.common, inputs) } pub fn verify(&self, proof: Proof) -> Result<()> { @@ -108,7 +102,7 @@ pub struct ProverCircuitData, const D: usize> { impl, const D: usize> ProverCircuitData { pub fn prove(&self, inputs: PartialWitness) -> Proof { - prove(&self.prover_only, &self.common, inputs, vec![]) + prove(&self.prover_only, &self.common, inputs) } } @@ -134,9 +128,10 @@ pub(crate) struct ProverOnlyCircuitData, const D: usize> { /// Subgroup of order `degree`. pub subgroup: Vec, /// The circuit's copy constraints. - pub copy_constraints: Vec<(Target, Target)>, + pub copy_constraints: Vec, /// The concrete placement of each gate in the circuit. pub gate_instances: Vec>, + pub marked_targets: Vec, } /// Circuit data required by the verifier, but not the prover. diff --git a/src/copy_constraint.rs b/src/copy_constraint.rs new file mode 100644 index 00000000..0798f2a8 --- /dev/null +++ b/src/copy_constraint.rs @@ -0,0 +1,21 @@ +use crate::target::Target; + +pub struct CopyConstraint { + pub pair: (Target, Target), + pub name: String, +} + +impl From<(Target, Target)> for CopyConstraint { + fn from(pair: (Target, Target)) -> Self { + Self { + pair, + name: String::default(), + } + } +} + +impl CopyConstraint { + pub fn new(pair: (Target, Target), name: String) -> Self { + Self { pair, name } + } +} diff --git a/src/fri/prover.rs b/src/fri/prover.rs index f937ee55..c0c37391 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -2,6 +2,7 @@ use crate::field::extension_field::{flatten, unflatten, Extendable}; use crate::field::field::Field; use crate::fri::FriConfig; use crate::hash::hash_n_to_1; +use crate::merkle_proofs::verify_merkle_proof; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; use crate::plonk_common::reduce_with_powers; @@ -139,6 +140,9 @@ fn fri_prover_query_round, const D: usize>( .iter() .map(|t| (t.get(x_index).to_vec(), t.prove(x_index))) .collect::>(); + for ((v, p), t) in initial_proof.iter().zip(initial_merkle_trees.iter()) { + verify_merkle_proof(v.clone(), x_index, t.root, p, false).unwrap(); + } for (i, tree) in trees.iter().enumerate() { let arity_bits = config.reduction_arity_bits[i]; let arity = 1 << arity_bits; diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index f76a7506..bfe0275f 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use env_logger::builder; use itertools::izip; @@ -89,7 +91,7 @@ impl, const D: usize> CircuitBuilder { // Size of the LDE domain. let n = proof.final_poly.len() << total_arities; - // Recover the random betas used in the FRI reductions. + self.set_context("Recover the random betas used in the FRI reductions."); let betas = proof .commit_phase_merkle_roots .iter() @@ -100,7 +102,7 @@ impl, const D: usize> CircuitBuilder { .collect::>(); challenger.observe_extension_elements(&proof.final_poly.0); - // Check PoW. + self.set_context("Check PoW"); self.fri_verify_proof_of_work(proof, challenger, config); // Check that parameters are coherent. @@ -136,7 +138,19 @@ impl, const D: usize> CircuitBuilder { proof: &FriInitialTreeProofTarget, initial_merkle_roots: &[HashTarget], ) { - for ((evals, merkle_proof), &root) in proof.evals_proofs.iter().zip(initial_merkle_roots) { + for (i, ((evals, merkle_proof), &root)) in proof + .evals_proofs + .iter() + .zip(initial_merkle_roots) + .enumerate() + { + self.set_context(&format!("Verify {}-th initial Merkle proof.", i)); + if i == 0 { + self.add_marked(Arc::new(evals.clone()), "Evals"); + self.add_marked(Arc::new(merkle_proof.siblings.clone()), "merkle proof"); + self.add_marked(Arc::new(root.clone()), "root"); + self.add_marked(Arc::new(x_index.clone()), "x_index"); + } self.verify_merkle_proof(evals.clone(), x_index, root, merkle_proof); } } @@ -262,6 +276,7 @@ impl, const D: usize> CircuitBuilder { x_index = self.split_low_high(x_index, n_log, 64).0; let mut x_index_num_bits = n_log; let mut domain_size = n; + self.set_context("Check FRI initial proof."); self.fri_verify_initial_proof( x_index, &round_proof.initial_trees_proof, @@ -304,6 +319,7 @@ impl, const D: usize> CircuitBuilder { self.split_low_high(x_index, arity_bits, x_index_num_bits); evals = self.insert(low_x_index, e_x, evals); evaluations.push(evals); + self.set_context("Verify FRI round Merkle proof."); self.verify_merkle_proof( flatten_target(&evaluations[i]), high_x_index, diff --git a/src/lib.rs b/src/lib.rs index 50c0bb4e..8461d201 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub mod circuit_builder; pub mod circuit_data; +pub mod copy_constraint; pub mod field; pub mod fri; pub mod gadgets; diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index fee57d19..96d42a5f 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use anyhow::{ensure, Result}; use crate::circuit_builder::CircuitBuilder; @@ -57,81 +59,6 @@ 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( @@ -149,6 +76,7 @@ impl, const D: usize> CircuitBuilder { let mut acc_leaf_index = zero; for (bit, &sibling) in purported_index_bits.into_iter().zip(&proof.siblings) { + self.add_marked(Arc::new(state), "current digest"); let gate = self .add_gate_no_constants(GMiMCGate::::with_automatic_constants()); @@ -203,7 +131,7 @@ impl, const D: usize> CircuitBuilder { 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) + self.named_assert_hashes_equal(state, merkle_root, "Check Merkle root".into()) } pub(crate) fn assert_hashes_equal(&mut self, x: HashTarget, y: HashTarget) { @@ -211,6 +139,16 @@ impl, const D: usize> CircuitBuilder { self.assert_equal(x.elements[i], y.elements[i]); } } + + pub(crate) fn named_assert_hashes_equal(&mut self, x: HashTarget, y: HashTarget, name: String) { + for i in 0..4 { + self.named_assert_equal( + x.elements[i], + y.elements[i], + format!("{}: {}-th hash element", name, i), + ); + } + } } #[cfg(test)] @@ -239,7 +177,6 @@ mod tests { 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; @@ -265,19 +202,70 @@ 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_marked(pw, marked); + let proof = data.prove(pw); + + verify(proof, &data.verifier_only, &data.common) + } + + #[test] + fn test_recursive_merkle_proof_yo() -> Result<()> { + type F = CrandallField; + type FF = QuarticCrandallField; + let config = CircuitConfig::large_config(); + let mut builder = CircuitBuilder::::new(config); + let mut pw = PartialWitness::new(); + + let eval = vec![ + 8165005271518921330, + 6083226207459673392, + 9958534500108693972, + 3430614617054831715, + 14276647488823198467, + 11751680815846448477, + 2771303161388554632, + 2371046485289351947, + 16743918419162514074, + 9932615810638040318, + 16314448410395528119, + 1511019414432045441, + 5645123553081661379, + 9778873694114674382, + 10629301051878288289, + 16655634835422730769, + 7474748727207643713, + 8501202586470516512, + 5612524789765317534, + 3026252715636633329, + 15131263578183166645, + 1869341605741303173, + 14645831398335944979, + 8356334351657818532, + 4888183615701827634, + 5994174007215505657, + 11524125964783895772, + 2202081323880269694, + 9827048951184368953, + 12675978139336549297, + 5868550852792001156, + ]; + let eval = eval + .into_iter() + .map(F::from_canonical_usize) + .collect::>(); + let data = builder.add_virtual_targets(eval.len()); + for j in 0..data.len() { + pw.set_target(data[j], eval[j]); + } + + dbg!(hash_or_noop(eval.clone())); + let hash = builder.hash_or_noop(data.clone()); + builder.add_marked(Arc::new(hash), "hash test"); + + let data = builder.build(); + let proof = data.prove(pw); verify(proof, &data.verifier_only, &data.common) } diff --git a/src/prover.rs b/src/prover.rs index aa0ecf30..4ff72608 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -27,7 +27,6 @@ pub(crate) fn prove, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, inputs: PartialWitness, - marked: Vec, ) -> Proof { let fri_config = &common_data.config.fri_config; let config = &common_data.config; @@ -45,6 +44,10 @@ pub(crate) fn prove, const D: usize>( "to generate witness" ); + for m in &prover_data.marked_targets { + m.display(&partial_witness); + } + timed!( partial_witness .check_copy_constraints(&prover_data.copy_constraints, &prover_data.gate_instances) @@ -57,10 +60,6 @@ pub(crate) fn prove, const D: usize>( "to compute full witness" ); - for m in marked { - m.display(&witness); - } - let wires_values: Vec> = timed!( witness .wire_values diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 46a52cd3..2557402a 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use env_logger::builder; use crate::circuit_builder::CircuitBuilder; @@ -33,6 +35,7 @@ impl, const D: usize> CircuitBuilder { let mut challenger = RecursiveChallenger::new(self); + self.set_context("Challenger observes proof and generates challenges."); let digest = HashTarget::from_vec(self.constants(&inner_common_data.circuit_digest.elements)); challenger.observe_hash(&digest); @@ -59,7 +62,7 @@ impl, const D: usize> CircuitBuilder { let partial_products = &proof.openings.partial_products; let zeta_pow_deg = self.exp_u64_extension(zeta, inner_common_data.degree() as u64); - // Evaluate the vanishing polynomial at our challenge point, zeta. + self.set_context("Evaluate the vanishing polynomial at our challenge point, zeta."); let vanishing_polys_zeta = eval_vanishing_poly_recursively( self, inner_common_data, @@ -78,9 +81,10 @@ impl, const D: usize> CircuitBuilder { marked.push(MarkedTargets { name: "vanishing polys".into(), - targets: Box::new(vanishing_polys_zeta[0].clone()), + targets: Arc::new(vanishing_polys_zeta[0].clone()), }); + self.set_context("Check vanishing and quotient polynomials."); let quotient_polys_zeta = &proof.openings.quotient_polys; let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); let z_h_zeta = self.sub_extension(zeta_pow_deg, one); @@ -91,7 +95,11 @@ 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); - self.route_extension(vanishing_polys_zeta[i], rhs); + self.named_route_extension( + vanishing_polys_zeta[i], + rhs, + format!("Vanishing polynomial == Z_H * quotient, challenge {}", i), + ); } let evaluations = proof.openings.clone(); @@ -355,8 +363,9 @@ mod tests { builder.add_recursive_verifier(pt, &config, &inner_data, &cd, &mut marked); dbg!(builder.num_gates()); + dbg!(builder.marked_targets.len()); let data = builder.build(); - let recursive_proof = data.prove_marked(pw, marked); + let recursive_proof = data.prove(pw); verify(recursive_proof, &data.verifier_only, &data.common).unwrap(); } diff --git a/src/util/marking.rs b/src/util/marking.rs index e4a13499..fd0a9e37 100644 --- a/src/util/marking.rs +++ b/src/util/marking.rs @@ -1,4 +1,5 @@ use std::convert::TryInto; +use std::sync::Arc; use crate::field::extension_field::target::ExtensionTarget; use crate::field::field::Field; @@ -6,7 +7,7 @@ use crate::proof::HashTarget; use crate::target::Target; use crate::witness::{PartialWitness, Witness}; -pub trait Markable { +pub trait Markable: 'static + Send + Sync { fn targets(&self) -> Vec; } @@ -34,20 +35,18 @@ impl Markable for Vec { } } +#[derive(Clone)] pub struct MarkedTargets { - pub targets: Box, + pub targets: Arc, pub name: String, } impl MarkedTargets { - pub fn display(&self, wit: &Witness) { + pub fn display(&self, pw: &PartialWitness) { let targets = self.targets.targets(); println!("Values for {}:", self.name); for &t in &targets { - match t { - Target::Wire(w) => println!("{}", wit.get_wire(w.gate, w.input)), - _ => println!("Not a wire."), - } + println!("{}", pw.get_target(t)); } println!("End of values for {}", self.name); } diff --git a/src/witness.rs b/src/witness.rs index 0f930971..8b46d43f 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -3,6 +3,7 @@ use std::convert::TryInto; use anyhow::{ensure, Result}; +use crate::copy_constraint::CopyConstraint; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; @@ -169,23 +170,23 @@ impl PartialWitness { /// Checks that the copy constraints are satisfied in the witness. pub fn check_copy_constraints( &self, - copy_constraints: &[(Target, Target)], + copy_constraints: &[CopyConstraint], gate_instances: &[GateInstance], ) -> Result<()> where F: Extendable, { - for &(a, b) in copy_constraints { + for CopyConstraint { pair: (a, b), name } in copy_constraints { // TODO: Take care of public inputs once they land. - let va = self.try_get_target(a).unwrap_or(F::ZERO); - let vb = self.try_get_target(b).unwrap_or(F::ZERO); - let desc = |t: Target| -> String { + let va = self.try_get_target(*a).unwrap_or(F::ZERO); + let vb = self.try_get_target(*b).unwrap_or(F::ZERO); + let desc = |t: &Target| -> String { match t { Target::Wire(Wire { gate, input }) => format!( "wire {} of gate #{} (`{}`)", input, gate, - gate_instances[gate].gate_type.0.id() + gate_instances[*gate].gate_type.0.id() ), Target::PublicInput { index } => format!("{}-th public input", index), Target::VirtualTarget { index } => format!("{}-th virtual target", index), @@ -193,8 +194,9 @@ impl PartialWitness { }; ensure!( va == vb, - "Copy constraint between {} and {} is not satisfied. \ + "Copy constraint '{}' between {} and {} is not satisfied. \ Got values of {} and {} respectively.", + name, desc(a), desc(b), va, From 92c4bba2a3f705d7ec8ba7770a9259972b4ee339 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 14 Jul 2021 21:16:04 +0200 Subject: [PATCH 10/21] Fix bug in GMiMC --- src/fri/recursive_verifier.rs | 6 ------ src/hash.rs | 4 +++- src/merkle_proofs.rs | 1 - 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index bfe0275f..acc4268e 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -145,12 +145,6 @@ impl, const D: usize> CircuitBuilder { .enumerate() { self.set_context(&format!("Verify {}-th initial Merkle proof.", i)); - if i == 0 { - self.add_marked(Arc::new(evals.clone()), "Evals"); - self.add_marked(Arc::new(merkle_proof.siblings.clone()), "merkle proof"); - self.add_marked(Arc::new(root.clone()), "root"); - self.add_marked(Arc::new(x_index.clone()), "x_index"); - } self.verify_merkle_proof(evals.clone(), x_index, root, merkle_proof); } } diff --git a/src/hash.rs b/src/hash.rs index 47d703cd..eb8e146b 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,5 +1,7 @@ //! Concrete instantiation of a hash function. +use std::sync::Arc; + use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::Extendable; use crate::field::field::Field; @@ -218,7 +220,7 @@ pub fn hash_n_to_m(mut inputs: Vec, num_outputs: usize, pad: bool) // Absorb all input chunks. for input_chunk in inputs.chunks(SPONGE_RATE) { for i in 0..input_chunk.len() { - state[i] += input_chunk[i]; + state[i] = input_chunk[i]; } state = permute(state); } diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index 96d42a5f..9e355a0d 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -76,7 +76,6 @@ impl, const D: usize> CircuitBuilder { let mut acc_leaf_index = zero; for (bit, &sibling) in purported_index_bits.into_iter().zip(&proof.siblings) { - self.add_marked(Arc::new(state), "current digest"); let gate = self .add_gate_no_constants(GMiMCGate::::with_automatic_constants()); From 514ee0feda685d7cc006f3e25e0fa8695bd5a5d9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 14 Jul 2021 21:52:34 +0200 Subject: [PATCH 11/21] More realistic config --- src/recursive_verifier.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 2557402a..7ee4f856 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -130,6 +130,7 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::target::ExtensionTarget; + use crate::fri::FriConfig; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::merkle_proofs::MerkleProofTarget; use crate::polynomial::commitment::OpeningProofTarget; @@ -333,12 +334,26 @@ mod tests { type F = CrandallField; type FF = QuarticCrandallField; const D: usize = 4; + let config = CircuitConfig { + num_wires: 134, + num_routed_wires: 28, + security_bits: 128, + rate_bits: 3, + num_challenges: 3, + fri_config: FriConfig { + proof_of_work_bits: 1, + rate_bits: 3, + reduction_arity_bits: vec![2, 2, 2, 2, 2, 2, 2], + num_query_rounds: 40, + }, + }; let (proof, vd, cd) = { - let config = CircuitConfig::large_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]); + let mut builder = CircuitBuilder::::new(config.clone()); + let two = builder.two(); + let two = builder.hash_n_to_hash(vec![two], true).elements[0]; + for i in 0..5000 { + let two = builder.mul(two, two); + } let data = builder.build(); ( data.prove(PartialWitness::new()), @@ -348,7 +363,6 @@ mod tests { }; verify(proof.clone(), &vd, &cd).unwrap(); - let config = CircuitConfig::large_config(); let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); let mut marked = Vec::new(); From 4a86e3dac2de3f02279dd640f5ee2be5570de561 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 14 Jul 2021 22:34:16 +0200 Subject: [PATCH 12/21] Optimize `get_sigma_map` --- src/permutation_argument.rs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/permutation_argument.rs b/src/permutation_argument.rs index 37ecf8d2..c3169285 100644 --- a/src/permutation_argument.rs +++ b/src/permutation_argument.rs @@ -118,22 +118,6 @@ pub struct WirePartitions { } impl WirePartitions { - /// Find a wire's "neighbor" in the context of Plonk's "extended copy constraints" check. In - /// other words, find the next wire in the given wire's partition. If the given wire is last in - /// its partition, this will loop around. If the given wire has a partition all to itself, it - /// is considered its own neighbor. - fn get_neighbor(&self, wire: Wire) -> Wire { - let partition = &self.partition[self.indices[&wire]]; - let n = partition.len(); - for i in 0..n { - if partition[i] == wire { - let neighbor_index = (i + 1) % n; - return partition[neighbor_index]; - } - } - panic!("Wire not found in the expected partition") - } - pub(crate) fn get_sigma_polys( &self, degree_log: usize, @@ -161,11 +145,22 @@ impl WirePartitions { debug_assert_eq!(self.indices.len() % degree, 0); let num_routed_wires = self.indices.len() / degree; + /// Find a wire's "neighbor" in the context of Plonk's "extended copy constraints" check. In + /// other words, find the next wire in the given wire's partition. If the given wire is last in + /// its partition, this will loop around. If the given wire has a partition all to itself, it + /// is considered its own neighbor. + let mut neighbors = HashMap::new(); + for subset in &self.partition { + for n in 0..subset.len() { + neighbors.insert(subset[n], subset[(n + 1) % subset.len()]); + } + } + let mut sigma = Vec::new(); for input in 0..num_routed_wires { for gate in 0..degree { let wire = Wire { gate, input }; - let neighbor = self.get_neighbor(wire); + let neighbor = neighbors[&wire]; sigma.push(neighbor.input * degree + neighbor.gate); } } From 0ba59163461c2b0e04680129f2bb69b8742be761 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 15 Jul 2021 09:11:54 +0200 Subject: [PATCH 13/21] Minor --- src/fri/prover.rs | 4 ---- src/polynomial/commitment.rs | 1 + src/recursive_verifier.rs | 7 ++----- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/fri/prover.rs b/src/fri/prover.rs index c0c37391..f937ee55 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -2,7 +2,6 @@ use crate::field::extension_field::{flatten, unflatten, Extendable}; use crate::field::field::Field; use crate::fri::FriConfig; use crate::hash::hash_n_to_1; -use crate::merkle_proofs::verify_merkle_proof; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; use crate::plonk_common::reduce_with_powers; @@ -140,9 +139,6 @@ fn fri_prover_query_round, const D: usize>( .iter() .map(|t| (t.get(x_index).to_vec(), t.prove(x_index))) .collect::>(); - for ((v, p), t) in initial_proof.iter().zip(initial_merkle_trees.iter()) { - verify_merkle_proof(v.clone(), x_index, t.root, p, false).unwrap(); - } for (i, tree) in trees.iter().enumerate() { let arity_bits = config.reduction_arity_bits[i]; let arity = 1 << arity_bits; diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 8e3a5579..6f48fe30 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -321,6 +321,7 @@ mod tests { use super::*; use crate::circuit_data::CircuitConfig; + use crate::fri::FriConfig; use crate::plonk_common::PlonkPolynomials; fn gen_random_test_case, const D: usize>( diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 7ee4f856..2f7a6d1e 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -119,8 +119,6 @@ impl, const D: usize> CircuitBuilder { inner_common_data, self, ); - dbg!(self.num_gates()); - dbg!(self.generators.len()); } } @@ -329,6 +327,7 @@ mod tests { } #[test] + #[ignore] fn test_recursive_verifier() { env_logger::init(); type F = CrandallField; @@ -351,7 +350,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 i in 0..5000 { + for i in 0..1000 { let two = builder.mul(two, two); } let data = builder.build(); @@ -376,8 +375,6 @@ mod tests { builder.add_recursive_verifier(pt, &config, &inner_data, &cd, &mut marked); - dbg!(builder.num_gates()); - dbg!(builder.marked_targets.len()); let data = builder.build(); let recursive_proof = data.prove(pw); From 7dec6efc6ce3531191214b77a3b132f67a5e2f66 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 15 Jul 2021 09:52:42 +0200 Subject: [PATCH 14/21] Rewrite Markable to avoid Arcs --- src/circuit_builder.rs | 5 ++- src/circuit_data.rs | 2 +- src/fri/recursive_verifier.rs | 2 -- src/hash.rs | 2 -- src/merkle_proofs.rs | 64 --------------------------------- src/recursive_verifier.rs | 15 +------- src/util/marking.rs | 67 ++++++++++++++++++++--------------- src/vanishing_poly.rs | 7 ---- src/witness.rs | 6 ++++ 9 files changed, 48 insertions(+), 122 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index a2c6d935..3b7db285 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -1,6 +1,5 @@ use std::collections::{HashMap, HashSet}; use std::convert::TryInto; -use std::sync::Arc; use std::time::Instant; use log::info; @@ -49,7 +48,7 @@ pub struct CircuitBuilder, const D: usize> { context: String, - pub marked_targets: Vec, + pub marked_targets: Vec>, /// Generators used to generate the witness. pub generators: Vec>>, @@ -308,7 +307,7 @@ impl, const D: usize> CircuitBuilder { self.context = new_context.to_string(); } - pub fn add_marked(&mut self, targets: Arc, name: &str) { + pub fn add_marked(&mut self, targets: Markable, name: &str) { self.marked_targets.push(MarkedTargets { targets, name: name.to_string(), diff --git a/src/circuit_data.rs b/src/circuit_data.rs index e2df2755..56b23e3c 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -131,7 +131,7 @@ pub(crate) struct ProverOnlyCircuitData, const D: usize> { pub copy_constraints: Vec, /// The concrete placement of each gate in the circuit. pub gate_instances: Vec>, - pub marked_targets: Vec, + pub marked_targets: Vec>, } /// Circuit data required by the verifier, but not the prover. diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index acc4268e..3faa9f08 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use env_logger::builder; use itertools::izip; diff --git a/src/hash.rs b/src/hash.rs index eb8e146b..fd551a6c 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,7 +1,5 @@ //! Concrete instantiation of a hash function. -use std::sync::Arc; - use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::Extendable; use crate::field::field::Field; diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index 9e355a0d..a4652ca1 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use anyhow::{ensure, Result}; use crate::circuit_builder::CircuitBuilder; @@ -10,7 +8,6 @@ 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)] @@ -161,7 +158,6 @@ 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; @@ -208,64 +204,4 @@ mod tests { verify(proof, &data.verifier_only, &data.common) } - - #[test] - fn test_recursive_merkle_proof_yo() -> Result<()> { - type F = CrandallField; - type FF = QuarticCrandallField; - let config = CircuitConfig::large_config(); - let mut builder = CircuitBuilder::::new(config); - let mut pw = PartialWitness::new(); - - let eval = vec![ - 8165005271518921330, - 6083226207459673392, - 9958534500108693972, - 3430614617054831715, - 14276647488823198467, - 11751680815846448477, - 2771303161388554632, - 2371046485289351947, - 16743918419162514074, - 9932615810638040318, - 16314448410395528119, - 1511019414432045441, - 5645123553081661379, - 9778873694114674382, - 10629301051878288289, - 16655634835422730769, - 7474748727207643713, - 8501202586470516512, - 5612524789765317534, - 3026252715636633329, - 15131263578183166645, - 1869341605741303173, - 14645831398335944979, - 8356334351657818532, - 4888183615701827634, - 5994174007215505657, - 11524125964783895772, - 2202081323880269694, - 9827048951184368953, - 12675978139336549297, - 5868550852792001156, - ]; - let eval = eval - .into_iter() - .map(F::from_canonical_usize) - .collect::>(); - let data = builder.add_virtual_targets(eval.len()); - for j in 0..data.len() { - pw.set_target(data[j], eval[j]); - } - - dbg!(hash_or_noop(eval.clone())); - let hash = builder.hash_or_noop(data.clone()); - builder.add_marked(Arc::new(hash), "hash test"); - - let data = builder.build(); - let proof = data.prove(pw); - - verify(proof, &data.verifier_only, &data.common) - } } diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 2f7a6d1e..940c0142 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -1,7 +1,3 @@ -use std::sync::Arc; - -use env_logger::builder; - use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; use crate::field::extension_field::Extendable; @@ -9,7 +5,6 @@ use crate::field::field::Field; use crate::gates::gate::{GateRef, PrefixedGate}; use crate::plonk_challenger::RecursiveChallenger; use crate::proof::{HashTarget, ProofTarget}; -use crate::util::marking::MarkedTargets; use crate::util::scaling::ReducingFactorTarget; use crate::vanishing_poly::eval_vanishing_poly_recursively; use crate::vars::EvaluationTargets; @@ -25,7 +20,6 @@ impl, const D: usize> CircuitBuilder { inner_config: &CircuitConfig, inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, - marked: &mut Vec, ) { assert!(self.config.num_wires >= MIN_WIRES); assert!(self.config.num_wires >= MIN_ROUTED_WIRES); @@ -76,14 +70,8 @@ impl, const D: usize> CircuitBuilder { &betas, &gammas, &alphas, - marked, ); - marked.push(MarkedTargets { - name: "vanishing polys".into(), - targets: Arc::new(vanishing_polys_zeta[0].clone()), - }); - self.set_context("Check vanishing and quotient polynomials."); let quotient_polys_zeta = &proof.openings.quotient_polys; let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); @@ -364,7 +352,6 @@ mod tests { 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); set_proof_target(&proof, &pt, &mut pw); @@ -373,7 +360,7 @@ mod tests { }; pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); - builder.add_recursive_verifier(pt, &config, &inner_data, &cd, &mut marked); + builder.add_recursive_verifier(pt, &config, &inner_data, &cd); let data = builder.build(); let recursive_proof = data.prove(pw); diff --git a/src/util/marking.rs b/src/util/marking.rs index fd0a9e37..fc689137 100644 --- a/src/util/marking.rs +++ b/src/util/marking.rs @@ -1,53 +1,62 @@ use std::convert::TryInto; -use std::sync::Arc; use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::proof::HashTarget; use crate::target::Target; use crate::witness::{PartialWitness, Witness}; -pub trait Markable: 'static + Send + Sync { - fn targets(&self) -> Vec; +#[derive(Clone)] +pub enum Markable { + Target(Target), + ExtensionTarget(ExtensionTarget), + HashTarget(HashTarget), + Vec(Vec>), } -impl Markable for Target { - fn targets(&self) -> Vec { - vec![*self] +impl From for Markable { + fn from(t: Target) -> Self { + Self::Target(t) + } +} +impl From> for Markable { + fn from(et: ExtensionTarget) -> Self { + Self::ExtensionTarget(et) + } +} +impl From for Markable { + fn from(ht: HashTarget) -> Self { + Self::HashTarget(ht) + } +} +impl>, const D: usize> From> for Markable { + fn from(v: Vec) -> Self { + Self::Vec(v.into_iter().map(|m| m.into()).collect()) } } -impl Markable for ExtensionTarget { - fn targets(&self) -> Vec { - self.0.try_into().unwrap() - } -} - -impl Markable for HashTarget { - fn targets(&self) -> Vec { - self.elements.try_into().unwrap() - } -} - -impl Markable for Vec { - fn targets(&self) -> Vec { - self.iter().flat_map(|m| m.targets()).collect() +impl Markable { + fn print_markable>(&self, pw: &PartialWitness) { + match self { + Markable::Target(t) => println!("{}", pw.get_target(*t)), + Markable::ExtensionTarget(et) => println!("{}", pw.get_extension_target(*et)), + Markable::HashTarget(ht) => println!("{:?}", pw.get_hash_target(*ht)), + Markable::Vec(v) => v.iter().for_each(|m| m.print_markable(pw)), + } } } #[derive(Clone)] -pub struct MarkedTargets { - pub targets: Arc, +pub struct MarkedTargets { + pub targets: Markable, pub name: String, } -impl MarkedTargets { - pub fn display(&self, pw: &PartialWitness) { - let targets = self.targets.targets(); +impl MarkedTargets { + pub fn display>(&self, pw: &PartialWitness) { println!("Values for {}:", self.name); - for &t in &targets { - println!("{}", pw.get_target(t)); - } + self.targets.print_markable(pw); println!("End of values for {}", self.name); } } diff --git a/src/vanishing_poly.rs b/src/vanishing_poly.rs index 6c336593..70d19230 100644 --- a/src/vanishing_poly.rs +++ b/src/vanishing_poly.rs @@ -335,7 +335,6 @@ pub fn evaluate_gate_constraints_recursively, const D: usize>( gates: &[PrefixedGate], num_gate_constraints: usize, vars: EvaluationTargets, - marked: &mut Vec, ) -> Vec> { let mut constraints = vec![builder.zero_extension(); num_gate_constraints]; for gate in gates { @@ -343,10 +342,6 @@ pub fn evaluate_gate_constraints_recursively, const D: usize>( .gate .0 .eval_filtered_recursively(builder, vars, &gate.prefix); - // marked.push(MarkedTargets { - // name: gate.gate.0.id(), - // targets: Box::new(gate_constraints.clone()), - // }); for (i, c) in gate_constraints.into_iter().enumerate() { constraints[i] = builder.add_extension(constraints[i], c); } @@ -370,7 +365,6 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( betas: &[Target], gammas: &[Target], alphas: &[Target], - marked: &mut Vec, ) -> Vec> { let max_degree = common_data.quotient_degree_factor; let (num_prods, final_num_prod) = common_data.num_partial_products; @@ -380,7 +374,6 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( &common_data.gates, common_data.num_gate_constraints, vars, - marked, ); // The L_1(x) (Z(x) - 1) vanishing terms. diff --git a/src/witness.rs b/src/witness.rs index 8b46d43f..1190fc8f 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -78,6 +78,12 @@ impl PartialWitness { ) } + pub fn get_hash_target(&self, ht: HashTarget) -> Hash { + Hash { + elements: self.get_targets(&ht.elements).try_into().unwrap(), + } + } + pub fn try_get_target(&self, target: Target) -> Option { self.target_values.get(&target).cloned() } From 2e12ee8e8237c1c186fa28424cca017659ee6a93 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 15 Jul 2021 10:13:13 +0200 Subject: [PATCH 15/21] Minor --- src/circuit_builder.rs | 6 +++--- src/circuit_data.rs | 1 - src/copy_constraint.rs | 2 +- src/fri/recursive_verifier.rs | 2 +- src/gadgets/arithmetic_extension.rs | 2 +- src/gates/gate.rs | 1 - src/generator.rs | 6 ------ src/merkle_proofs.rs | 1 + src/polynomial/commitment.rs | 8 ++------ src/prover.rs | 3 --- src/witness.rs | 1 - 11 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 3b7db285..8bedf562 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -51,7 +51,7 @@ pub struct CircuitBuilder, const D: usize> { pub marked_targets: Vec>, /// Generators used to generate the witness. - pub generators: Vec>>, + generators: Vec>>, constants_to_targets: HashMap, targets_to_constants: HashMap, @@ -361,7 +361,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn blind_and_pad(&mut self) { + fn blind_and_pad(&mut self) { let (regular_poly_openings, z_openings) = self.blinding_counts(); info!( "Adding {} blinding terms for witness polynomials, and {}*2 for Z polynomials", @@ -414,7 +414,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn constant_polys( + fn constant_polys( &self, gates: &[PrefixedGate], num_constants: usize, diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 56b23e3c..e6c9a8e0 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -9,7 +9,6 @@ use crate::fri::FriConfig; use crate::gates::gate::{GateInstance, PrefixedGate}; use crate::generator::WitnessGenerator; use crate::polynomial::commitment::ListPolynomialCommitment; -use crate::polynomial::polynomial::PolynomialValues; use crate::proof::{Hash, HashTarget, Proof}; use crate::prover::prove; use crate::target::Target; diff --git a/src/copy_constraint.rs b/src/copy_constraint.rs index 0798f2a8..f1f1d3d9 100644 --- a/src/copy_constraint.rs +++ b/src/copy_constraint.rs @@ -9,7 +9,7 @@ impl From<(Target, Target)> for CopyConstraint { fn from(pair: (Target, Target)) -> Self { Self { pair, - name: String::default(), + name: String::new(), } } } diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 3faa9f08..99e21622 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -190,7 +190,7 @@ impl, const D: usize> CircuitBuilder { .copied() .collect::>(); let mut single_numerator = alpha.reduce(&single_evals, self); - // TODO: Precompute the rhs as it is the same in all FRI round. + // TODO: Precompute the rhs as it is the same in all FRI rounds. let rhs = alpha.reduce(&single_openings, self); single_numerator = self.sub_extension(single_numerator, rhs); let single_denominator = self.sub_extension(subgroup_x, zeta); diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 49748040..57968a23 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -459,7 +459,7 @@ mod tests { let config = CircuitConfig::large_config(); - let mut builder = CircuitBuilder::::new(config.clone()); + let mut builder = CircuitBuilder::::new(config); let x = FF::rand(); let y = FF::rand(); diff --git a/src/gates/gate.rs b/src/gates/gate.rs index 49b610ba..9b45817e 100644 --- a/src/gates/gate.rs +++ b/src/gates/gate.rs @@ -8,7 +8,6 @@ use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::gates::gate_tree::Tree; use crate::generator::WitnessGenerator; -use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A custom gate. diff --git a/src/generator.rs b/src/generator.rs index ee2001ec..a47c5267 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -55,12 +55,6 @@ pub(crate) fn generate_partial_witness( pending_generator_indices = next_pending_generator_indices; } - for i in 0..generators.len() { - if !expired_generator_indices.contains(&i) { - dbg!(i); - break; - } - } assert_eq!( expired_generator_indices.len(), generators.len(), diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index a4652ca1..74bdf67d 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -124,6 +124,7 @@ impl, const D: usize> CircuitBuilder { ) } + // TODO: this is far from optimal. let leaf_index_rev = self.reverse_limbs::<2>(leaf_index, height); self.assert_equal(acc_leaf_index, leaf_index_rev); diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 6f48fe30..7c580ad9 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -20,7 +20,6 @@ use crate::util::{log2_ceil, log2_strict, reverse_bits, reverse_index_bits_in_pl pub const SALT_SIZE: usize = 2; pub struct ListPolynomialCommitment { - pub original_values: Vec>, // TODO: Remove when debugging is done. pub polynomials: Vec>, pub merkle_tree: MerkleTree, pub degree: usize, @@ -42,7 +41,7 @@ impl ListPolynomialCommitment { "to compute LDE" ); - Self::new_from_data(values, polynomials, lde_values, degree, rate_bits, blinding) + Self::new_from_data(polynomials, lde_values, degree, rate_bits, blinding) } /// Creates a list polynomial commitment for the polynomials `polynomials`. @@ -52,17 +51,15 @@ impl ListPolynomialCommitment { blinding: bool, ) -> Self { let degree = polynomials[0].len(); - let values = polynomials.iter().map(|p| p.clone().fft()).collect(); let lde_values = timed!( Self::lde_values(&polynomials, rate_bits, blinding), "to compute LDE" ); - Self::new_from_data(values, polynomials, lde_values, degree, rate_bits, blinding) + Self::new_from_data(polynomials, lde_values, degree, rate_bits, blinding) } fn new_from_data( - values: Vec>, polynomials: Vec>, lde_values: Vec>, degree: usize, @@ -74,7 +71,6 @@ impl ListPolynomialCommitment { let merkle_tree = timed!(MerkleTree::new(leaves, false), "to build Merkle tree"); Self { - original_values: values, polynomials, merkle_tree, degree, diff --git a/src/prover.rs b/src/prover.rs index 4ff72608..d328299a 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::time::Instant; use log::info; @@ -6,7 +5,6 @@ use rayon::prelude::*; use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; use crate::field::extension_field::Extendable; -use crate::field::field::Field; use crate::generator::generate_partial_witness; use crate::plonk_challenger::Challenger; use crate::plonk_common::{PlonkPolynomials, ZeroPolyOnCoset}; @@ -14,7 +12,6 @@ use crate::polynomial::commitment::ListPolynomialCommitment; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::Proof; use crate::timed; -use crate::util::marking::MarkedTargets; use crate::util::partial_products::partial_products; use crate::util::{log2_ceil, transpose}; use crate::vanishing_poly::{ diff --git a/src/witness.rs b/src/witness.rs index 1190fc8f..ac555f82 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -183,7 +183,6 @@ impl PartialWitness { F: Extendable, { for CopyConstraint { pair: (a, b), name } in copy_constraints { - // TODO: Take care of public inputs once they land. let va = self.try_get_target(*a).unwrap_or(F::ZERO); let vb = self.try_get_target(*b).unwrap_or(F::ZERO); let desc = |t: &Target| -> String { From 7d41785ac692390a75ecfc24fc590939e23a4cf0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 15 Jul 2021 10:24:11 +0200 Subject: [PATCH 16/21] Comments --- src/circuit_builder.rs | 4 +++- src/circuit_data.rs | 1 + src/copy_constraint.rs | 1 + src/prover.rs | 1 + src/util/marking.rs | 4 ++++ 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 8bedf562..db78819f 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -46,9 +46,11 @@ pub struct CircuitBuilder, const D: usize> { copy_constraints: Vec, + /// A context string used to give context to copy constraints. context: String, - pub marked_targets: Vec>, + /// A vector of marked targets. The values assigned to these targets will be displayed by the prover. + marked_targets: Vec>, /// Generators used to generate the witness. generators: Vec>>, diff --git a/src/circuit_data.rs b/src/circuit_data.rs index e6c9a8e0..8f422b93 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -130,6 +130,7 @@ pub(crate) struct ProverOnlyCircuitData, const D: usize> { pub copy_constraints: Vec, /// The concrete placement of each gate in the circuit. pub gate_instances: Vec>, + /// A vector of marked targets. The values assigned to these targets will be displayed by the prover. pub marked_targets: Vec>, } diff --git a/src/copy_constraint.rs b/src/copy_constraint.rs index f1f1d3d9..dc64924a 100644 --- a/src/copy_constraint.rs +++ b/src/copy_constraint.rs @@ -1,5 +1,6 @@ use crate::target::Target; +/// A named copy constraint. pub struct CopyConstraint { pub pair: (Target, Target), pub name: String, diff --git a/src/prover.rs b/src/prover.rs index d328299a..25243c0a 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -41,6 +41,7 @@ pub(crate) fn prove, const D: usize>( "to generate witness" ); + // Display the marked targets for debugging purposes. for m in &prover_data.marked_targets { m.display(&partial_witness); } diff --git a/src/util/marking.rs b/src/util/marking.rs index fc689137..228c46b1 100644 --- a/src/util/marking.rs +++ b/src/util/marking.rs @@ -7,6 +7,7 @@ use crate::proof::HashTarget; use crate::target::Target; use crate::witness::{PartialWitness, Witness}; +/// Enum representing all types of targets, so that they can be marked. #[derive(Clone)] pub enum Markable { Target(Target), @@ -37,6 +38,7 @@ impl>, const D: usize> From> for Markable { } impl Markable { + /// Display a `Markable` by querying a partial witness. fn print_markable>(&self, pw: &PartialWitness) { match self { Markable::Target(t) => println!("{}", pw.get_target(*t)), @@ -47,6 +49,7 @@ impl Markable { } } +/// A named collection of targets. #[derive(Clone)] pub struct MarkedTargets { pub targets: Markable, @@ -54,6 +57,7 @@ pub struct MarkedTargets { } impl MarkedTargets { + /// Display the collection of targets along with its name by querying a partial witness. pub fn display>(&self, pw: &PartialWitness) { println!("Values for {}:", self.name); self.targets.print_markable(pw); From fe05da67201af359f771dbeba8f06633c2f9a28d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 15 Jul 2021 10:39:57 +0200 Subject: [PATCH 17/21] Clipp --- src/circuit_data.rs | 1 - src/fri/recursive_verifier.rs | 9 +-- src/gadgets/arithmetic_extension.rs | 1 - src/gadgets/interpolation.rs | 2 +- src/gates/base_sum.rs | 1 - src/gates/gmimc.rs | 2 - src/merkle_proofs.rs | 4 +- src/merkle_tree.rs | 2 +- src/permutation_argument.rs | 8 +-- src/plonk_challenger.rs | 1 - src/plonk_common.rs | 4 -- src/prover.rs | 6 +- src/recursive_verifier.rs | 16 ++--- src/util/marking.rs | 5 +- src/util/scaling.rs | 5 +- src/vanishing_poly.rs | 107 +--------------------------- src/verifier.rs | 2 +- src/witness.rs | 2 +- 18 files changed, 23 insertions(+), 155 deletions(-) diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 8f422b93..e389ed27 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -11,7 +11,6 @@ use crate::generator::WitnessGenerator; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::proof::{Hash, HashTarget, Proof}; use crate::prover::prove; -use crate::target::Target; use crate::util::marking::MarkedTargets; use crate::verifier::verify; use crate::witness::PartialWitness; diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 99e21622..5bbd5e80 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -1,6 +1,3 @@ -use env_logger::builder; -use itertools::izip; - use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CommonCircuitData; use crate::field::extension_field::target::{flatten_target, ExtensionTarget}; @@ -120,7 +117,7 @@ impl, const D: usize> CircuitBuilder { zeta, alpha, initial_merkle_roots, - &proof, + proof, challenger, n, &betas, @@ -205,7 +202,7 @@ impl, const D: usize> CircuitBuilder { .take(common_data.zs_range().end) .map(|&e| self.convert_to_ext(e)) .collect::>(); - let mut zs_composition_eval = alpha.clone().reduce(&zs_evals, self); + let 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); @@ -229,7 +226,7 @@ impl, const D: usize> CircuitBuilder { .iter() .map(|&e| self.convert_to_ext(e)) .collect::>(); - let mut wire_composition_eval = alpha.clone().reduce(&wire_evals, self); + let 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); diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 57968a23..f308d1fc 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -447,7 +447,6 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; - use crate::fri::FriConfig; use crate::verifier::verify; use crate::witness::PartialWitness; diff --git a/src/gadgets/interpolation.rs b/src/gadgets/interpolation.rs index 8ece6063..a531515c 100644 --- a/src/gadgets/interpolation.rs +++ b/src/gadgets/interpolation.rs @@ -65,7 +65,7 @@ mod tests { use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::FieldExtension; use crate::field::field::Field; - use crate::field::interpolation::{interpolant, interpolate}; + use crate::field::interpolation::interpolant; use crate::verifier::verify; use crate::witness::PartialWitness; diff --git a/src/gates/base_sum.rs b/src/gates/base_sum.rs index e34aa6c1..8f453d8e 100644 --- a/src/gates/base_sum.rs +++ b/src/gates/base_sum.rs @@ -170,7 +170,6 @@ impl SimpleGenerator for BaseSplitGenerator { #[cfg(test)] mod tests { - use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::gates::base_sum::BaseSumGate; use crate::gates::gate_testing::test_low_degree; diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 4f23a46e..e12668a3 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -325,8 +325,6 @@ mod tests { use crate::gates::gmimc::{GMiMCGate, W}; use crate::generator::generate_partial_witness; use crate::gmimc::gmimc_permute_naive; - use crate::permutation_argument::TargetPartition; - use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::verifier::verify; use crate::wire::Wire; diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index 74bdf67d..a9aeeb27 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -157,7 +157,6 @@ mod tests { use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; - use crate::merkle_proofs::verify_merkle_proof; use crate::merkle_tree::MerkleTree; use crate::verifier::verify; use crate::witness::PartialWitness; @@ -169,7 +168,6 @@ mod tests { #[test] 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(); @@ -177,7 +175,7 @@ mod tests { let log_n = 8; let n = 1 << log_n; let leaves = random_data::(n, 7); - let tree = MerkleTree::new(leaves.clone(), false); + let tree = MerkleTree::new(leaves, false); let i: usize = thread_rng().gen_range(0, n); let proof = tree.prove(i); diff --git a/src/merkle_tree.rs b/src/merkle_tree.rs index ed092cff..d6fa8694 100644 --- a/src/merkle_tree.rs +++ b/src/merkle_tree.rs @@ -114,7 +114,7 @@ mod tests { let leaves = random_data::(n, 7); verify_all_leaves(leaves.clone(), n, false)?; - verify_all_leaves(leaves.clone(), n, true)?; + verify_all_leaves(leaves, n, true)?; Ok(()) } diff --git a/src/permutation_argument.rs b/src/permutation_argument.rs index c3169285..ca5a228f 100644 --- a/src/permutation_argument.rs +++ b/src/permutation_argument.rs @@ -145,10 +145,10 @@ impl WirePartitions { debug_assert_eq!(self.indices.len() % degree, 0); let num_routed_wires = self.indices.len() / degree; - /// Find a wire's "neighbor" in the context of Plonk's "extended copy constraints" check. In - /// other words, find the next wire in the given wire's partition. If the given wire is last in - /// its partition, this will loop around. If the given wire has a partition all to itself, it - /// is considered its own neighbor. + // Find a wire's "neighbor" in the context of Plonk's "extended copy constraints" check. In + // other words, find the next wire in the given wire's partition. If the given wire is last in + // its partition, this will loop around. If the given wire has a partition all to itself, it + // is considered its own neighbor. let mut neighbors = HashMap::new(); for subset in &self.partition { for n in 0..subset.len() { diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index da7253f0..f48cbbf1 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -346,7 +346,6 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::field::Field; use crate::generator::generate_partial_witness; - use crate::permutation_argument::TargetPartition; use crate::plonk_challenger::{Challenger, RecursiveChallenger}; use crate::target::Target; use crate::witness::PartialWitness; diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 2c3a0817..6fd0c393 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -1,16 +1,12 @@ use std::borrow::Borrow; use crate::circuit_builder::CircuitBuilder; -use crate::circuit_data::CommonCircuitData; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field::Field; -use crate::gates::gate::{GateRef, PrefixedGate}; use crate::polynomial::commitment::SALT_SIZE; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; -use crate::util::partial_products::check_partial_products; -use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// Holds the Merkle tree index and blinding flag of a set of polynomials used in FRI. #[derive(Debug, Copy, Clone)] diff --git a/src/prover.rs b/src/prover.rs index 25243c0a..cefe165f 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -14,10 +14,8 @@ use crate::proof::Proof; use crate::timed; use crate::util::partial_products::partial_products; use crate::util::{log2_ceil, transpose}; -use crate::vanishing_poly::{ - eval_vanishing_poly_base, evaluate_gate_constraints, evaluate_gate_constraints_base, yoba, -}; -use crate::vars::{EvaluationVars, EvaluationVarsBase}; +use crate::vanishing_poly::eval_vanishing_poly_base; +use crate::vars::EvaluationVarsBase; use crate::witness::{PartialWitness, Witness}; pub(crate) fn prove, const D: usize>( diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 940c0142..1bd58c2a 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -1,8 +1,6 @@ use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; use crate::field::extension_field::Extendable; -use crate::field::field::Field; -use crate::gates::gate::{GateRef, PrefixedGate}; use crate::plonk_challenger::RecursiveChallenger; use crate::proof::{HashTarget, ProofTarget}; use crate::util::scaling::ReducingFactorTarget; @@ -114,17 +112,14 @@ impl, const D: usize> CircuitBuilder { 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::fri::FriConfig; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::merkle_proofs::MerkleProofTarget; use crate::polynomial::commitment::OpeningProofTarget; use crate::proof::{ FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, - HashTarget, OpeningSetTarget, Proof, + OpeningSetTarget, Proof, }; - use crate::target::Target; use crate::verifier::verify; use crate::witness::PartialWitness; @@ -319,7 +314,6 @@ mod tests { fn test_recursive_verifier() { env_logger::init(); type F = CrandallField; - type FF = QuarticCrandallField; const D: usize = 4; let config = CircuitConfig { num_wires: 134, @@ -336,10 +330,10 @@ mod tests { }; let (proof, 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 i in 0..1000 { - let two = builder.mul(two, two); + let _two = builder.two(); + let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; + for _ in 0..1000 { + let _two = builder.mul(_two, _two); } let data = builder.build(); ( diff --git a/src/util/marking.rs b/src/util/marking.rs index 228c46b1..758d583e 100644 --- a/src/util/marking.rs +++ b/src/util/marking.rs @@ -1,11 +1,8 @@ -use std::convert::TryInto; - use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field::Field; use crate::proof::HashTarget; use crate::target::Target; -use crate::witness::{PartialWitness, Witness}; +use crate::witness::PartialWitness; /// Enum representing all types of targets, so that they can be marked. #[derive(Clone)] diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 6effc5db..e2cedfb8 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -187,10 +187,7 @@ mod tests { let mut builder = CircuitBuilder::::new(config); let alpha = FF::rand(); - let alpha = FF::ONE; - let vs = (0..n) - .map(|i| FF::from_canonical_usize(i)) - .collect::>(); + let vs = (0..n).map(FF::from_canonical_usize).collect::>(); let manual_reduce = ReducingFactor::new(alpha).reduce(vs.iter()); let manual_reduce = builder.constant_extension(manual_reduce); diff --git a/src/vanishing_poly.rs b/src/vanishing_poly.rs index 70d19230..d176e57b 100644 --- a/src/vanishing_poly.rs +++ b/src/vanishing_poly.rs @@ -3,11 +3,10 @@ use crate::circuit_data::CommonCircuitData; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field::Field; -use crate::gates::gate::{Gate, GateRef, PrefixedGate}; +use crate::gates::gate::PrefixedGate; use crate::plonk_common; -use crate::plonk_common::{eval_l_1, eval_l_1_recursively, ZeroPolyOnCoset}; +use crate::plonk_common::{eval_l_1_recursively, ZeroPolyOnCoset}; use crate::target::Target; -use crate::util::marking::MarkedTargets; use crate::util::partial_products::{check_partial_products, check_partial_products_recursively}; use crate::util::scaling::ReducingFactorTarget; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; @@ -185,108 +184,6 @@ pub(crate) fn eval_vanishing_poly_base, const D: usize>( plonk_common::reduce_with_powers_multi(&vanishing_terms, alphas) } -pub(crate) fn yoba, const D: usize>( - common_data: &CommonCircuitData, - index: usize, - x: F, - vars: EvaluationVarsBase, - local_zs: &[F], - next_zs: &[F], - partial_products: &[F], - s_sigmas: &[F], - betas: &[F], - gammas: &[F], - alphas: &[F], -) -> Vec { - let max_degree = common_data.quotient_degree_factor; - let (num_prods, final_num_prod) = common_data.num_partial_products; - - let constraint_terms = - evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars); - - // The L_1(x) (Z(x) - 1) vanishing terms. - let mut vanishing_z_1_terms = Vec::new(); - // The terms checking the partial products. - let mut vanishing_partial_products_terms = Vec::new(); - // The Z(x) f'(x) - g'(x) Z(g x) terms. - let mut vanishing_v_shift_terms = Vec::new(); - - for i in 0..common_data.config.num_challenges { - let z_x = local_zs[i]; - let z_gz = next_zs[i]; - vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::ONE)); - - let numerator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let k_i = common_data.k_is[j]; - let s_id = k_i * x; - wire_value + betas[i] * s_id + gammas[i] - }) - .collect::>(); - let denominator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = vars.local_wires[j]; - let s_sigma = s_sigmas[j]; - wire_value + betas[i] * s_sigma + gammas[i] - }) - .collect::>(); - let quotient_values = (0..common_data.config.num_routed_wires) - .map(|j| numerator_values[j] / denominator_values[j]) - .collect::>(); - - // The partial products considered for this iteration of `i`. - let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; - // Check the numerator partial products. - let mut partial_product_check = - check_partial_products("ient_values, current_partial_products, max_degree); - // The first checks are of the form `q - n/d` which is a rational function not a polynomial. - // We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials. - denominator_values - .chunks(max_degree) - .zip(partial_product_check.iter_mut()) - .for_each(|(d, q)| { - *q *= d.iter().copied().product(); - }); - vanishing_partial_products_terms.extend(partial_product_check); - - // The quotient final product is the product of the last `final_num_prod` elements. - let quotient: F = current_partial_products[num_prods - final_num_prod..] - .iter() - .copied() - .product(); - assert_eq!( - quotient, - numerator_values.iter().copied().product::() - / denominator_values.iter().copied().product::() - ); - vanishing_v_shift_terms.push(quotient * z_x - z_gz); - } - - if vanishing_z_1_terms.iter().any(|x| !x.is_zero()) { - dbg!(&vanishing_z_1_terms); - } - if vanishing_partial_products_terms - .iter() - .any(|x| !x.is_zero()) - { - dbg!(&vanishing_partial_products_terms); - } - if vanishing_v_shift_terms.iter().any(|x| !x.is_zero()) { - dbg!(&vanishing_v_shift_terms); - } - if constraint_terms.iter().any(|x| !x.is_zero()) { - dbg!(&constraint_terms); - } - [ - vanishing_z_1_terms, - vanishing_partial_products_terms, - vanishing_v_shift_terms, - constraint_terms, - ] - .concat() -} - /// Evaluates all gate constraints. /// /// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not diff --git a/src/verifier.rs b/src/verifier.rs index 864a2c15..ce438449 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -4,7 +4,7 @@ use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{eval_zero_poly, reduce_with_powers}; +use crate::plonk_common::reduce_with_powers; use crate::proof::Proof; use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::EvaluationVars; diff --git a/src/witness.rs b/src/witness.rs index ac555f82..25885ba3 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -117,7 +117,7 @@ impl PartialWitness { pub fn set_hash_target(&mut self, ht: HashTarget, value: Hash) { ht.elements - .into_iter() + .iter() .zip(value.elements) .for_each(|(&t, x)| self.set_target(t, x)); } From a6bc83217b4b4daf87b697f4c30f7002908a23da Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 15 Jul 2021 10:55:18 +0200 Subject: [PATCH 18/21] Minor --- src/circuit_builder.rs | 4 ++-- src/recursive_verifier.rs | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index db78819f..cc47d290 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -42,11 +42,11 @@ pub struct CircuitBuilder, const D: usize> { public_input_index: usize, /// The next available index for a `VirtualTarget`. - pub virtual_target_index: usize, + virtual_target_index: usize, copy_constraints: Vec, - /// A context string used to give context to copy constraints. + /// A string used to give context to copy constraints. context: String, /// A vector of marked targets. The values assigned to these targets will be displayed by the prover. diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 1bd58c2a..3e48850e 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -73,12 +73,12 @@ impl, const D: usize> CircuitBuilder { self.set_context("Check vanishing and quotient polynomials."); let quotient_polys_zeta = &proof.openings.quotient_polys; let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); + let mut scale = ReducingFactorTarget::new(zeta_pow_deg); let z_h_zeta = self.sub_extension(zeta_pow_deg, one); for (i, chunk) in quotient_polys_zeta .chunks(inner_common_data.quotient_degree_factor) .enumerate() { - let mut scale = ReducingFactorTarget::new(zeta_pow_deg); let mut rhs = scale.reduce(chunk, self); rhs = self.mul_extension(z_h_zeta, rhs); self.named_route_extension( @@ -123,6 +123,7 @@ mod tests { use crate::verifier::verify; use crate::witness::PartialWitness; + // Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`. fn get_fri_query_round, const D: usize>( proof: &Proof, builder: &mut CircuitBuilder, @@ -155,6 +156,7 @@ mod tests { query_round } + // Construct a `ProofTarget` with the same dimensions as `proof`. fn proof_to_proof_target, const D: usize>( proof: &Proof, builder: &mut CircuitBuilder, @@ -206,6 +208,7 @@ mod tests { } } + // Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. fn set_proof_target, const D: usize>( proof: &Proof, pt: &ProofTarget, @@ -332,7 +335,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..1000 { + for _ in 0..5000 { let _two = builder.mul(_two, _two); } let data = builder.build(); From 4bc06deed82448a938205f1c4c9188d93259eb1f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 15 Jul 2021 10:59:53 +0200 Subject: [PATCH 19/21] `zs_root` -> `zs_partial_products_root` --- src/fri/recursive_verifier.rs | 2 +- src/fri/verifier.rs | 2 +- src/proof.rs | 4 ++-- src/prover.rs | 2 +- src/recursive_verifier.rs | 11 +++++++---- src/verifier.rs | 4 ++-- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 5bbd5e80..056cc78d 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -165,7 +165,7 @@ impl, const D: usize> CircuitBuilder { // - one for polynomials opened at `x` and `g x` // - one for polynomials opened at `x` and `x.frobenius()` - // Polynomials opened at `x`, i.e., the constants, sigmas and quotient polynomials. + // Polynomials opened at `x`, i.e., the constants, sigmas, quotient and partial products polynomials. let single_evals = [ PlonkPolynomials::CONSTANTS_SIGMAS, PlonkPolynomials::QUOTIENT, diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 5ff068b6..90fc907f 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -163,7 +163,7 @@ fn fri_combine_initial, const D: usize>( // - one for Zs, which are opened at `x` and `g x` // - one for wire polynomials, which are opened at `x` and `x.frobenius()` - // Polynomials opened at `x`, i.e., the constants, sigmas and quotient polynomials. + // Polynomials opened at `x`, i.e., the constants, sigmas, quotient and partial products polynomials. let single_evals = [ PlonkPolynomials::CONSTANTS_SIGMAS, PlonkPolynomials::QUOTIENT, diff --git a/src/proof.rs b/src/proof.rs index 353a0080..b5875927 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -66,7 +66,7 @@ pub struct Proof, const D: usize> { /// Merkle root of LDEs of wire values. pub wires_root: Hash, /// Merkle root of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_root: Hash, + pub plonk_zs_partial_products_root: Hash, /// Merkle root of LDEs of the quotient polynomial components. pub quotient_polys_root: Hash, /// Purported values of each polynomial at the challenge point. @@ -77,7 +77,7 @@ pub struct Proof, const D: usize> { pub struct ProofTarget { pub wires_root: HashTarget, - pub plonk_zs_root: HashTarget, + pub plonk_zs_partial_products_root: HashTarget, pub quotient_polys_root: HashTarget, pub openings: OpeningSetTarget, pub opening_proof: OpeningProofTarget, diff --git a/src/prover.rs b/src/prover.rs index cefe165f..0411ce09 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -180,7 +180,7 @@ pub(crate) fn prove, const D: usize>( Proof { wires_root: wires_commitment.merkle_tree.root, - plonk_zs_root: zs_partial_products_commitment.merkle_tree.root, + plonk_zs_partial_products_root: zs_partial_products_commitment.merkle_tree.root, quotient_polys_root: quotient_polys_commitment.merkle_tree.root, openings, opening_proof, diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 3e48850e..ed28c73f 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -36,7 +36,7 @@ impl, const D: usize> CircuitBuilder { let betas = challenger.get_n_challenges(self, num_challenges); let gammas = challenger.get_n_challenges(self, num_challenges); - challenger.observe_hash(&proof.plonk_zs_root); + challenger.observe_hash(&proof.plonk_zs_partial_products_root); let alphas = challenger.get_n_challenges(self, num_challenges); challenger.observe_hash(&proof.quotient_polys_root); @@ -93,7 +93,7 @@ impl, const D: usize> CircuitBuilder { let merkle_roots = &[ inner_verifier_data.constants_sigmas_root, proof.wires_root, - proof.plonk_zs_root, + proof.plonk_zs_partial_products_root, proof.quotient_polys_root, ]; @@ -201,7 +201,7 @@ mod tests { ProofTarget { wires_root, - plonk_zs_root, + plonk_zs_partial_products_root: plonk_zs_root, quotient_polys_root, openings, opening_proof, @@ -215,7 +215,10 @@ mod tests { pw: &mut PartialWitness, ) { pw.set_hash_target(pt.wires_root, proof.wires_root); - pw.set_hash_target(pt.plonk_zs_root, proof.plonk_zs_root); + pw.set_hash_target( + pt.plonk_zs_partial_products_root, + proof.plonk_zs_partial_products_root, + ); pw.set_hash_target(pt.quotient_polys_root, proof.quotient_polys_root); for (&t, &x) in pt.openings.wires.iter().zip(&proof.openings.wires) { diff --git a/src/verifier.rs b/src/verifier.rs index ce438449..6b4df627 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -26,7 +26,7 @@ pub(crate) fn verify, const D: usize>( let betas = challenger.get_n_challenges(num_challenges); let gammas = challenger.get_n_challenges(num_challenges); - challenger.observe_hash(&proof.plonk_zs_root); + challenger.observe_hash(&proof.plonk_zs_partial_products_root); let alphas = challenger.get_n_challenges(num_challenges); challenger.observe_hash(&proof.quotient_polys_root); @@ -78,7 +78,7 @@ pub(crate) fn verify, const D: usize>( let merkle_roots = &[ verifier_data.constants_sigmas_root, proof.wires_root, - proof.plonk_zs_root, + proof.plonk_zs_partial_products_root, proof.quotient_polys_root, ]; From 097413479e76372a2ac92296422e0d54e0db5f3d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sun, 18 Jul 2021 10:35:42 +0200 Subject: [PATCH 20/21] PR feedback --- src/gadgets/arithmetic_extension.rs | 13 +++++++++++++ src/gates/gmimc.rs | 5 ++--- src/permutation_argument.rs | 1 + src/recursive_verifier.rs | 13 +++++-------- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index f308d1fc..71af783c 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -292,6 +292,19 @@ impl, const D: usize> CircuitBuilder { b } + /// Exponentiate `base` to the power of `2^power_log`. + // TODO: Test + pub fn exp_power_of_2( + &mut self, + mut base: ExtensionTarget, + power_log: usize, + ) -> ExtensionTarget { + for _ in 0..power_log { + base = self.square_extension(base); + } + base + } + /// Exponentiate `base` to the power of a known `exponent`. // TODO: Test pub fn exp_u64_extension( diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index e12668a3..60ad3cd5 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -134,8 +134,7 @@ impl, const D: usize, const R: usize> Gate for GMiMCGate< let old_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_OLD]; let new_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_NEW]; // computed_new_index_acc = 2 * old_index_acc + swap - let two = builder.two(); - let two = builder.convert_to_ext(two); + let two = builder.two_extension(); let computed_new_index_acc = builder.mul_add_extension(two, old_index_acc, swap); constraints.push(builder.sub_extension(computed_new_index_acc, new_index_acc)); @@ -436,7 +435,7 @@ mod tests { assert_eq!(ev.len(), ev_t.len()); for (e, e_t) in ev.into_iter().zip(ev_t) { let e_c = builder.constant_extension(e); - builder.route_extension(e_c, e_t); + builder.assert_equal_extension(e_c, e_t); } let data = builder.build(); diff --git a/src/permutation_argument.rs b/src/permutation_argument.rs index ca5a228f..5c1ead6a 100644 --- a/src/permutation_argument.rs +++ b/src/permutation_argument.rs @@ -114,6 +114,7 @@ impl usize> TargetPartition { pub struct WirePartitions { partition: Vec>, + // TODO: We don't need `indices` anymore, so we can delete it. indices: HashMap, } diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index ed28c73f..d9310b04 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -53,7 +53,7 @@ impl, const D: usize> CircuitBuilder { let s_sigmas = &proof.openings.plonk_sigmas; let partial_products = &proof.openings.partial_products; - let zeta_pow_deg = self.exp_u64_extension(zeta, inner_common_data.degree() as u64); + let zeta_pow_deg = self.exp_power_of_2(zeta, inner_common_data.degree_bits); self.set_context("Evaluate the vanishing polynomial at our challenge point, zeta."); let vanishing_polys_zeta = eval_vanishing_poly_recursively( self, @@ -72,24 +72,21 @@ impl, const D: usize> CircuitBuilder { self.set_context("Check vanishing and quotient polynomials."); let quotient_polys_zeta = &proof.openings.quotient_polys; - let zeta_pow_deg = self.exp_u64_extension(zeta, 1 << inner_common_data.degree_bits as u64); let mut scale = ReducingFactorTarget::new(zeta_pow_deg); let z_h_zeta = self.sub_extension(zeta_pow_deg, one); for (i, chunk) in quotient_polys_zeta .chunks(inner_common_data.quotient_degree_factor) .enumerate() { - let mut rhs = scale.reduce(chunk, self); - rhs = self.mul_extension(z_h_zeta, rhs); + let recombined_quotient = scale.reduce(chunk, self); + let computed_vanishing_poly = self.mul_extension(z_h_zeta, recombined_quotient); self.named_route_extension( vanishing_polys_zeta[i], - rhs, + computed_vanishing_poly, format!("Vanishing polynomial == Z_H * quotient, challenge {}", i), ); } - let evaluations = proof.openings.clone(); - let merkle_roots = &[ inner_verifier_data.constants_sigmas_root, proof.wires_root, @@ -99,7 +96,7 @@ impl, const D: usize> CircuitBuilder { proof.opening_proof.verify( zeta, - &evaluations, + &proof.openings, merkle_roots, &mut challenger, inner_common_data, From b7d51db9798d9d90f5095df826c84321bdd6a8b7 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 19 Jul 2021 07:11:40 +0200 Subject: [PATCH 21/21] Fix merge problems --- src/merkle_proofs.rs | 1 - src/polynomial/commitment.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index b7625f63..7b7cb67a 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -158,7 +158,6 @@ mod tests { use super::*; use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; - use crate::field::extension_field::quartic::QuarticCrandallField; use crate::merkle_tree::MerkleTree; use crate::verifier::verify; use crate::witness::PartialWitness; diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 4436a454..0b9e5bb0 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -248,10 +248,10 @@ impl ListPolynomialCommitment { } } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "")] pub struct OpeningProof, const D: usize> { - fri_proof: FriProof, + pub(crate) fri_proof: FriProof, // TODO: Get the degree from `CommonCircuitData` instead. quotient_degree: usize, } @@ -283,7 +283,7 @@ impl, const D: usize> OpeningProof { } pub struct OpeningProofTarget { - fri_proof: FriProofTarget, + pub(crate) fri_proof: FriProofTarget, } impl OpeningProofTarget {