From b50a9809dbc596d4c4da5a4b18d3ca078430328e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 8 Jul 2021 17:16:26 +0200 Subject: [PATCH] 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,