Start recursive verifier test

This commit is contained in:
wborgeaud 2021-07-08 17:16:26 +02:00
parent 7ab21a4f13
commit b50a9809db
6 changed files with 268 additions and 17 deletions

View File

@ -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<F: Extendable<D>, 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<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
(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<HashTarget> {
(0..n).map(|_i| self.add_virtual_hash()).collect()
}
pub fn add_virtual_extension_target(&mut self) -> ExtensionTarget<D> {
ExtensionTarget(self.add_virtual_targets(D).try_into().unwrap())
}
pub fn add_virtual_extension_targets(&mut self, n: usize) -> Vec<ExtensionTarget<D>> {
(0..n)
.map(|_i| self.add_virtual_extension_target())
.collect()
}
pub fn add_gate_no_constants(&mut self, gate_type: GateRef<F, D>) -> usize {
self.add_gate(gate_type, Vec::new())
}

View File

@ -16,6 +16,7 @@ pub struct MerkleProof<F: Field> {
pub siblings: Vec<Hash<F>>,
}
#[derive(Clone)]
pub struct MerkleProofTarget {
/// The Merkle digest of each sibling subtree, staying from the bottommost layer.
pub siblings: Vec<HashTarget>,

View File

@ -246,7 +246,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
}
pub struct OpeningProof<F: Field + Extendable<D>, const D: usize> {
fri_proof: FriProof<F, D>,
pub fri_proof: FriProof<F, D>,
// TODO: Get the degree from `CommonCircuitData` instead.
quotient_degree: usize,
}
@ -278,7 +278,7 @@ impl<F: Field + Extendable<D>, const D: usize> OpeningProof<F, D> {
}
pub struct OpeningProofTarget<const D: usize> {
fri_proof: FriProofTarget<D>,
pub fri_proof: FriProofTarget<D>,
}
#[cfg(test)]

View File

@ -61,7 +61,7 @@ impl HashTarget {
}
}
pub struct Proof<F: Field + Extendable<D>, const D: usize> {
pub struct Proof<F: Extendable<D>, const D: usize> {
/// Merkle root of LDEs of wire values.
pub wires_root: Hash<F>,
/// Merkle root of LDEs of Z, in the context of Plonk's permutation argument.
@ -78,8 +78,8 @@ pub struct ProofTarget<const D: usize> {
pub wires_root: HashTarget,
pub plonk_zs_root: HashTarget,
pub quotient_polys_root: HashTarget,
pub openings: Vec<OpeningSetTarget<D>>,
pub opening_proof: Vec<OpeningProofTarget<D>>,
pub openings: OpeningSetTarget<D>,
pub opening_proof: OpeningProofTarget<D>,
}
/// Evaluations and Merkle proof produced by the prover in a FRI query step.
@ -88,6 +88,7 @@ pub struct FriQueryStep<F: Field + Extendable<D>, const D: usize> {
pub merkle_proof: MerkleProof<F>,
}
#[derive(Clone)]
pub struct FriQueryStepTarget<const D: usize> {
pub evals: Vec<ExtensionTarget<D>>,
pub merkle_proof: MerkleProofTarget,
@ -106,6 +107,7 @@ impl<F: Field> FriInitialTreeProof<F> {
}
}
#[derive(Clone)]
pub struct FriInitialTreeProofTarget {
pub evals_proofs: Vec<(Vec<Target>, MerkleProofTarget)>,
}
@ -123,6 +125,7 @@ pub struct FriQueryRound<F: Field + Extendable<D>, const D: usize> {
pub steps: Vec<FriQueryStep<F, D>>,
}
#[derive(Clone)]
pub struct FriQueryRoundTarget<const D: usize> {
pub initial_trees_proof: FriInitialTreeProofTarget,
pub steps: Vec<FriQueryStepTarget<D>>,
@ -198,5 +201,6 @@ pub struct OpeningSetTarget<const D: usize> {
pub wires: Vec<ExtensionTarget<D>>,
pub plonk_zs: Vec<ExtensionTarget<D>>,
pub plonk_zs_right: Vec<ExtensionTarget<D>>,
pub partial_products: Vec<ExtensionTarget<D>>,
pub quotient_polys: Vec<ExtensionTarget<D>>,
}

View File

@ -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<F: Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
inner_config: CircuitConfig,
inner_circuit: VerifierCircuitTarget,
inner_gates: Vec<GateRef<F, D>>,
inner_proof: ProofTarget<D>,
) {
assert!(builder.config.num_wires >= MIN_WIRES);
assert!(builder.config.num_wires >= MIN_ROUTED_WIRES);
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Recursively verifies an inner proof.
pub fn add_recursive_verifier(
&mut self,
inner_config: CircuitConfig,
inner_circuit: VerifierCircuitTarget,
inner_gates: Vec<GateRef<F, D>>,
inner_proof: ProofTarget<D>,
) {
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<F: Extendable<D>, const D: usize>(
proof: &Proof<F, D>,
builder: &mut CircuitBuilder<F, D>,
) -> ProofTarget<D> {
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<F: Extendable<D>, const D: usize>(
proof: &Proof<F, D>,
pt: &ProofTarget<D>,
pw: &mut PartialWitness<F>,
) {
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::<F, 4>::new(config);
let zero = builder.zero();
let data = builder.build();
data.prove(PartialWitness::new())
};
let config = CircuitConfig::large_config();
let mut builder = CircuitBuilder::<F, 4>::new(config);
let mut pw = PartialWitness::new();
let pt = proof_to_proof_target(&proof, &mut builder);
set_proof_target(&proof, &pt, &mut pw);
}
}

View File

@ -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<F: Field> PartialWitness<F> {
}
}
pub fn set_hash_target(&mut self, ht: HashTarget, value: Hash<F>) {
ht.elements
.into_iter()
.zip(value.elements)
.for_each(|(&t, x)| self.set_target(t, x));
}
pub fn set_extension_target<const D: usize>(
&mut self,
et: ExtensionTarget<D>,