From b6f6c210187fef36485b86426b36920dd5831148 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 15 Jan 2023 00:06:08 -0800 Subject: [PATCH] Block circuit --- evm/src/fixed_recursive_verifier.rs | 94 ++++++++++++++++++++++++++++- plonky2/src/gates/selectors.rs | 2 +- plonky2/src/plonk/circuit_data.rs | 16 ++--- 3 files changed, 101 insertions(+), 11 deletions(-) diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index 5a3a5013..96dc3e93 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -3,6 +3,7 @@ use std::ops::Range; use itertools::Itertools; use plonky2::field::extension::Extendable; +use plonky2::fri::FriParams; use plonky2::gates::noop::NoopGate; use plonky2::hash::hash_types::RichField; use plonky2::hash::hashing::SPONGE_WIDTH; @@ -10,7 +11,9 @@ use plonky2::iop::challenger::RecursiveChallenger; use plonky2::iop::target::{BoolTarget, Target}; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, VerifierCircuitTarget}; +use plonky2::plonk::circuit_data::{ + CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget, +}; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; use plonky2::recursion::cyclic_recursion::check_cyclic_proof_verifier_data; @@ -50,6 +53,8 @@ where /// The EVM root circuit, which aggregates the (shrunk) per-table recursive proofs. pub root: RootCircuitData, pub aggregation: AggregationCircuitData, + /// The block circuit, which verifies an aggregation root proof and a previous block proof. + pub block: BlockCircuitData, /// Holds chains of circuits for each table and for each initial `degree_bits`. by_table: [RecursiveCircuitsForTable; NUM_TABLES], } @@ -90,10 +95,22 @@ pub struct AggregationChildTarget { evm_proof: ProofWithPublicInputsTarget, } -impl AllRecursiveCircuits +pub struct BlockCircuitData where F: RichField + Extendable, C: GenericConfig, +{ + circuit: CircuitData, + has_parent_block: BoolTarget, + parent_block_proof: ProofWithPublicInputsTarget, + agg_root_proof: ProofWithPublicInputsTarget, + cyclic_vk: VerifierCircuitTarget, +} + +impl AllRecursiveCircuits +where + F: RichField + Extendable, + C: GenericConfig + 'static, C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, [(); CpuStark::::COLUMNS]:, @@ -147,9 +164,11 @@ where let by_table = [cpu, keccak, keccak_sponge, logic, memory]; let root = Self::create_root_circuit(&by_table, stark_config); let aggregation = Self::create_aggregation_circuit(&root); + let block = Self::create_block_circuit(&aggregation); Self { root, aggregation, + block, by_table, } } @@ -298,6 +317,44 @@ where } } + fn create_block_circuit(agg: &AggregationCircuitData) -> BlockCircuitData { + // The block circuit is similar to the agg circuit; both verify two inner proofs. + // We need to adjust a few things, but it's easier than making a new CommonCircuitData. + let expected_common_data = CommonCircuitData { + fri_params: FriParams { + degree_bits: 14, + ..agg.circuit.common.fri_params.clone() + }, + ..agg.circuit.common.clone() + }; + + let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); + let has_parent_block = builder.add_virtual_bool_target_safe(); + let parent_block_proof = builder.add_virtual_proof_with_pis::(&expected_common_data); + let agg_root_proof = builder.add_virtual_proof_with_pis::(&agg.circuit.common); + + let cyclic_vk = builder.add_verifier_data_public_inputs(); + builder + .conditionally_verify_cyclic_proof_or_dummy::( + has_parent_block, + &parent_block_proof, + &expected_common_data, + ) + .expect("Failed to build cyclic recursion circuit"); + + let agg_verifier_data = builder.constant_verifier_data(&agg.circuit.verifier_only); + builder.verify_proof::(&agg_root_proof, &agg_verifier_data, &agg.circuit.common); + + let circuit = builder.build::(); + BlockCircuitData { + circuit, + has_parent_block, + parent_block_proof, + agg_root_proof, + cyclic_vk, + } + } + /// Create a proof for each STARK, then combine them, eventually culminating in a root proof. pub fn prove_root( &self, @@ -375,6 +432,39 @@ where &self.aggregation.circuit.common, ) } + + pub fn prove_block( + &self, + opt_parent_block_proof: Option<&ProofWithPublicInputs>, + agg_root_proof: &ProofWithPublicInputs, + ) -> anyhow::Result> { + let mut block_inputs = PartialWitness::new(); + + block_inputs.set_bool_target( + self.block.has_parent_block, + opt_parent_block_proof.is_some(), + ); + if let Some(parent_block_proof) = opt_parent_block_proof { + block_inputs + .set_proof_with_pis_target(&self.block.parent_block_proof, parent_block_proof); + } + + block_inputs.set_proof_with_pis_target(&self.block.agg_root_proof, agg_root_proof); + + block_inputs + .set_verifier_data_target(&self.block.cyclic_vk, &self.block.circuit.verifier_only); + + self.block.circuit.prove(block_inputs) + } + + pub fn verify_block(&self, block_proof: &ProofWithPublicInputs) -> anyhow::Result<()> { + self.block.circuit.verify(block_proof.clone())?; + check_cyclic_proof_verifier_data( + block_proof, + &self.block.circuit.verifier_only, + &self.block.circuit.common, + ) + } } struct RecursiveCircuitsForTable diff --git a/plonky2/src/gates/selectors.rs b/plonky2/src/gates/selectors.rs index 7c5c6f34..7217de2f 100644 --- a/plonky2/src/gates/selectors.rs +++ b/plonky2/src/gates/selectors.rs @@ -11,7 +11,7 @@ use crate::hash::hash_types::RichField; pub(crate) const UNUSED_SELECTOR: usize = u32::MAX as usize; #[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) struct SelectorsInfo { +pub struct SelectorsInfo { pub(crate) selector_indices: Vec, pub(crate) groups: Vec>, } diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index c57e206d..78d8125c 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -272,30 +272,30 @@ pub struct VerifierOnlyCircuitData, const D: usize> { pub struct CommonCircuitData, const D: usize> { pub config: CircuitConfig, - pub(crate) fri_params: FriParams, + pub fri_params: FriParams, /// The types of gates used in this circuit, along with their prefixes. - pub(crate) gates: Vec>, + pub gates: Vec>, /// Information on the circuit's selector polynomials. - pub(crate) selectors_info: SelectorsInfo, + pub selectors_info: SelectorsInfo, /// The degree of the PLONK quotient polynomial. - pub(crate) quotient_degree_factor: usize, + pub quotient_degree_factor: usize, /// The largest number of constraints imposed by any gate. - pub(crate) num_gate_constraints: usize, + pub num_gate_constraints: usize, /// The number of constant wires. - pub(crate) num_constants: usize, + pub num_constants: usize, pub num_public_inputs: usize, /// The `{k_i}` valued used in `S_ID_i` in Plonk's permutation argument. - pub(crate) k_is: Vec, + pub k_is: Vec, /// The number of partial products needed to compute the `Z` polynomials. - pub(crate) num_partial_products: usize, + pub num_partial_products: usize, } impl, const D: usize> CommonCircuitData {