From c9eed2bbf935c8da540df11de53edd2a78ed3497 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 7 Aug 2023 21:00:32 +0200 Subject: [PATCH] Connect public values in aggregation circuit (#1169) * Connect public values in aggregation circuit * Minor --- evm/src/fixed_recursive_verifier.rs | 45 +++++++- evm/src/proof.rs | 165 +++++++++++++++++++++++++++- 2 files changed, 206 insertions(+), 4 deletions(-) diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index 8d9cb59f..8e3bfb62 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -42,7 +42,9 @@ use crate::memory::{NUM_CHANNELS, VALUE_LIMBS}; use crate::permutation::{ get_grand_product_challenge_set_target, GrandProductChallenge, GrandProductChallengeSet, }; -use crate::proof::{PublicValues, PublicValuesTarget, StarkProofWithMetadata}; +use crate::proof::{ + BlockMetadataTarget, PublicValues, PublicValuesTarget, StarkProofWithMetadata, TrieRootsTarget, +}; use crate::prover::prove; use crate::recursive_verifier::{ add_common_recursion_gates, add_virtual_public_values, recursive_stark_circuit, @@ -223,6 +225,15 @@ impl AggregationChildTarget { evm_proof, }) } + + pub fn public_values>( + &self, + builder: &mut CircuitBuilder, + ) -> PublicValuesTarget { + let agg_pv = PublicValuesTarget::from_public_inputs(&self.agg_proof.public_inputs); + let evm_pv = PublicValuesTarget::from_public_inputs(&self.evm_proof.public_inputs); + PublicValuesTarget::select(builder, self.is_agg, agg_pv, evm_pv) + } } #[derive(Eq, PartialEq, Debug)] @@ -703,6 +714,38 @@ where let lhs = Self::add_agg_child(&mut builder, root); let rhs = Self::add_agg_child(&mut builder, root); + let lhs_public_values = lhs.public_values(&mut builder); + let rhs_public_values = rhs.public_values(&mut builder); + // Connect all block metadata values. + BlockMetadataTarget::connect( + &mut builder, + public_values.block_metadata, + lhs_public_values.block_metadata, + ); + BlockMetadataTarget::connect( + &mut builder, + public_values.block_metadata, + rhs_public_values.block_metadata, + ); + // Connect aggregation `trie_roots_before` with lhs `trie_roots_before`. + TrieRootsTarget::connect( + &mut builder, + public_values.trie_roots_before, + lhs_public_values.trie_roots_before, + ); + // Connect aggregation `trie_roots_after` with rhs `trie_roots_after`. + TrieRootsTarget::connect( + &mut builder, + public_values.trie_roots_after, + rhs_public_values.trie_roots_after, + ); + // Connect lhs `trie_roots_after` with rhs `trie_roots_before`. + TrieRootsTarget::connect( + &mut builder, + lhs_public_values.trie_roots_after, + rhs_public_values.trie_roots_before, + ); + // Pad to match the root circuit's degree. while log2_ceil(builder.num_gates()) < root.circuit.common.degree_bits() { builder.add_gate(NoopGate, vec![]); diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 0356473a..67fb0dc9 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -9,7 +9,8 @@ use plonky2::fri::structure::{ use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::ext_target::ExtensionTarget; -use plonky2::iop::target::Target; +use plonky2::iop::target::{BoolTarget, Target}; +use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{GenericConfig, Hasher}; use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use plonky2_maybe_rayon::*; @@ -160,16 +161,111 @@ impl PublicValuesTarget { cpu_trace_len, }) } + + pub fn from_public_inputs(pis: &[Target]) -> Self { + assert!(pis.len() > TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE); + Self { + trie_roots_before: TrieRootsTarget::from_public_inputs(&pis[0..TrieRootsTarget::SIZE]), + trie_roots_after: TrieRootsTarget::from_public_inputs( + &pis[TrieRootsTarget::SIZE..TrieRootsTarget::SIZE * 2], + ), + block_metadata: BlockMetadataTarget::from_public_inputs( + &pis[TrieRootsTarget::SIZE * 2 + ..TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE], + ), + cpu_trace_len: pis[TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE], + } + } + + pub fn select, const D: usize>( + builder: &mut CircuitBuilder, + condition: BoolTarget, + pv0: Self, + pv1: Self, + ) -> Self { + Self { + trie_roots_before: TrieRootsTarget::select( + builder, + condition, + pv0.trie_roots_before, + pv1.trie_roots_before, + ), + trie_roots_after: TrieRootsTarget::select( + builder, + condition, + pv0.trie_roots_after, + pv1.trie_roots_after, + ), + block_metadata: BlockMetadataTarget::select( + builder, + condition, + pv0.block_metadata, + pv1.block_metadata, + ), + cpu_trace_len: builder.select(condition, pv0.cpu_trace_len, pv1.cpu_trace_len), + } + } } -#[derive(Eq, PartialEq, Debug)] +#[derive(Eq, PartialEq, Debug, Copy, Clone)] pub struct TrieRootsTarget { pub state_root: [Target; 8], pub transactions_root: [Target; 8], pub receipts_root: [Target; 8], } -#[derive(Eq, PartialEq, Debug)] +impl TrieRootsTarget { + const SIZE: usize = 24; + + pub fn from_public_inputs(pis: &[Target]) -> Self { + let state_root = pis[0..8].try_into().unwrap(); + let transactions_root = pis[8..16].try_into().unwrap(); + let receipts_root = pis[16..24].try_into().unwrap(); + + Self { + state_root, + transactions_root, + receipts_root, + } + } + + pub fn select, const D: usize>( + builder: &mut CircuitBuilder, + condition: BoolTarget, + tr0: Self, + tr1: Self, + ) -> Self { + Self { + state_root: core::array::from_fn(|i| { + builder.select(condition, tr0.state_root[i], tr1.state_root[i]) + }), + transactions_root: core::array::from_fn(|i| { + builder.select( + condition, + tr0.transactions_root[i], + tr1.transactions_root[i], + ) + }), + receipts_root: core::array::from_fn(|i| { + builder.select(condition, tr0.receipts_root[i], tr1.receipts_root[i]) + }), + } + } + + pub fn connect, const D: usize>( + builder: &mut CircuitBuilder, + tr0: Self, + tr1: Self, + ) { + for i in 0..8 { + builder.connect(tr0.state_root[i], tr1.state_root[i]); + builder.connect(tr0.transactions_root[i], tr1.transactions_root[i]); + builder.connect(tr0.receipts_root[i], tr1.receipts_root[i]); + } + } +} + +#[derive(Eq, PartialEq, Debug, Copy, Clone)] pub struct BlockMetadataTarget { pub block_beneficiary: [Target; 5], pub block_timestamp: Target, @@ -180,6 +276,69 @@ pub struct BlockMetadataTarget { pub block_base_fee: Target, } +impl BlockMetadataTarget { + const SIZE: usize = 11; + + pub fn from_public_inputs(pis: &[Target]) -> Self { + let block_beneficiary = pis[0..5].try_into().unwrap(); + let block_timestamp = pis[5]; + let block_number = pis[6]; + let block_difficulty = pis[7]; + let block_gaslimit = pis[8]; + let block_chain_id = pis[9]; + let block_base_fee = pis[10]; + + Self { + block_beneficiary, + block_timestamp, + block_number, + block_difficulty, + block_gaslimit, + block_chain_id, + block_base_fee, + } + } + + pub fn select, const D: usize>( + builder: &mut CircuitBuilder, + condition: BoolTarget, + bm0: Self, + bm1: Self, + ) -> Self { + Self { + block_beneficiary: core::array::from_fn(|i| { + builder.select( + condition, + bm0.block_beneficiary[i], + bm1.block_beneficiary[i], + ) + }), + block_timestamp: builder.select(condition, bm0.block_timestamp, bm1.block_timestamp), + block_number: builder.select(condition, bm0.block_number, bm1.block_number), + block_difficulty: builder.select(condition, bm0.block_difficulty, bm1.block_difficulty), + block_gaslimit: builder.select(condition, bm0.block_gaslimit, bm1.block_gaslimit), + block_chain_id: builder.select(condition, bm0.block_chain_id, bm1.block_chain_id), + block_base_fee: builder.select(condition, bm0.block_base_fee, bm1.block_base_fee), + } + } + + pub fn connect, const D: usize>( + builder: &mut CircuitBuilder, + bm0: Self, + bm1: Self, + ) { + for i in 0..5 { + builder.connect(bm0.block_beneficiary[i], bm1.block_beneficiary[i]); + } + builder.connect(bm0.block_timestamp, bm1.block_timestamp); + builder.connect(bm0.block_number, bm1.block_number); + builder.connect(bm0.block_difficulty, bm1.block_difficulty); + builder.connect(bm0.block_gaslimit, bm1.block_gaslimit); + builder.connect(bm0.block_chain_id, bm1.block_chain_id); + builder.connect(bm0.block_base_fee, bm1.block_base_fee); + } +} + #[derive(Debug, Clone)] pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values.