From fc5f610df7dac85141c33bd8391a1ee8ee335385 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Fri, 16 Jun 2023 09:53:59 +0200 Subject: [PATCH] Refactor with Daniel's input --- evm/src/fixed_recursive_verifier.rs | 231 +++++++--------------------- evm/src/proof.rs | 34 +--- evm/src/recursive_verifier.rs | 53 +------ evm/tests/empty_txn_list.rs | 9 +- 4 files changed, 67 insertions(+), 260 deletions(-) diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index f6b6c32654..de72ed29e4 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -37,31 +37,27 @@ use crate::logic::LogicStark; use crate::memory::memory_stark::MemoryStark; use crate::permutation::{get_grand_product_challenge_set_target, GrandProductChallengeSet}; use crate::proof::{ - AggregatedPublicValues, AggregatedPublicValuesTarget, BlockMetadataTarget, - StarkProofWithMetadata, TrieRootsTarget, + BlockMetadataTarget, PublicValues, PublicValuesTarget, StarkProofWithMetadata, TrieRootsTarget, }; use crate::prover::prove; use crate::recursive_verifier::{ - add_common_recursion_gates, add_virtual_aggregated_public_values, recursive_stark_circuit, - set_aggregated_public_value_targets, PlonkWrapperCircuit, PublicInputs, StarkWrapperCircuit, + add_common_recursion_gates, add_virtual_public_values, recursive_stark_circuit, + set_public_value_targets, PlonkWrapperCircuit, PublicInputs, StarkWrapperCircuit, }; use crate::stark::Stark; /// An EVM proof, corresponding to either a root, an aggregation, or a block proof, /// along with public memory values. #[derive(Debug, Clone)] -pub struct EvmProof, C: GenericConfig, const D: usize> -where - [(); C::HCO::WIDTH]:, -{ +pub struct EvmProof, C: GenericConfig, const D: usize> { pub proof: ProofWithPublicInputs, - pub public_values: AggregatedPublicValues, + pub public_values: PublicValues, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct EvmProofTarget { pub proof: ProofWithPublicInputsTarget, - pub public_values: AggregatedPublicValuesTarget, + pub public_values: PublicValuesTarget, } impl EvmProofTarget { @@ -72,7 +68,7 @@ impl EvmProofTarget { pub fn from_buffer(buffer: &mut Buffer) -> IoResult { let proof = buffer.read_target_proof_with_public_inputs()?; - let public_values = AggregatedPublicValuesTarget::from_buffer(buffer)?; + let public_values = PublicValuesTarget::from_buffer(buffer)?; Ok(Self { proof, @@ -87,7 +83,7 @@ fn add_virtual_evm_proof, const D: usize>( common_data: &CommonCircuitData, ) -> EvmProofTarget { let proof = builder.add_virtual_proof_with_pis(common_data); - let public_values = add_virtual_aggregated_public_values(builder); + let public_values = add_virtual_public_values(builder); EvmProofTarget { proof, public_values, @@ -102,11 +98,10 @@ fn set_evm_proof_target( F: RichField + Extendable, C: GenericConfig, W: Witness, - C::Hasher: AlgebraicHasher, - [(); C::HCO::WIDTH]:, + C::Hasher: AlgebraicHasher, { witness.set_proof_with_pis_target(&evm_proof_target.proof, &evm_proof.proof); - set_aggregated_public_value_targets( + set_public_value_targets( witness, &evm_proof_target.public_values, &evm_proof.public_values, @@ -140,44 +135,13 @@ where } } -/// Selects `bm0` or `bm1` based on `b`, i.e., this returns `if b { bm0 } else { bm1 }`. -fn select_block_metadata, const D: usize>( - builder: &mut CircuitBuilder, - b: BoolTarget, - bm0: &BlockMetadataTarget, - bm1: &BlockMetadataTarget, -) -> BlockMetadataTarget -where - F: RichField + Extendable, -{ - let block_beneficiary: [Target; 5] = core::array::from_fn(|i| { - builder.select(b, bm0.block_beneficiary[i], bm1.block_beneficiary[i]) - }); - let block_timestamp = builder.select(b, bm0.block_timestamp, bm1.block_timestamp); - let block_number = builder.select(b, bm0.block_number, bm1.block_number); - let block_difficulty = builder.select(b, bm0.block_difficulty, bm1.block_difficulty); - let block_gaslimit = builder.select(b, bm0.block_gaslimit, bm1.block_gaslimit); - let block_chain_id = builder.select(b, bm0.block_chain_id, bm1.block_chain_id); - let block_base_fee = builder.select(b, bm0.block_base_fee, bm1.block_base_fee); - - BlockMetadataTarget { - block_beneficiary, - block_timestamp, - block_number, - block_difficulty, - block_gaslimit, - block_chain_id, - block_base_fee, - } -} - /// Selects `pv0` or `pv1` based on `b`, i.e., this returns `if b { pv0 } else { pv1 }`. fn select_public_values, const D: usize>( builder: &mut CircuitBuilder, b: BoolTarget, - pv0: &AggregatedPublicValuesTarget, - pv1: &AggregatedPublicValuesTarget, -) -> AggregatedPublicValuesTarget + pv0: &PublicValuesTarget, + pv1: &PublicValuesTarget, +) -> PublicValuesTarget where F: RichField + Extendable, { @@ -186,66 +150,51 @@ where let trie_roots_after = select_trie_roots(builder, b, &pv0.trie_roots_after, &pv1.trie_roots_after); - let block_metadata_pair = ( - select_block_metadata( - builder, - b, - &pv0.block_metadata_pair.0, - &pv1.block_metadata_pair.0, - ), - select_block_metadata( - builder, - b, - &pv0.block_metadata_pair.1, - &pv1.block_metadata_pair.1, - ), - ); - - AggregatedPublicValuesTarget { + PublicValuesTarget { trie_roots_before, trie_roots_after, - block_metadata_pair, + block_metadata: pv0.block_metadata.clone(), } } -/// Connect trie roots across two consecutive proofs. -/// If we combine two proofs representing chunks from a same block, -/// `connect_intra_roots` boolean target should be activated, to -/// enforce consistency between the intermediary transaction/receipt tries. +/// Connect trie roots across two consecutive proofs within a same block. fn connect_trie_roots, const D: usize>( builder: &mut CircuitBuilder, - connect_intra_roots: BoolTarget, x: &TrieRootsTarget, y: &TrieRootsTarget, ) where F: RichField + Extendable, { - connect_state_roots(builder, x, y); - - let zero = builder.zero(); + for (&limb0, &limb1) in x.state_root.iter().zip(&y.state_root) { + builder.connect(limb0, limb1); + } for (&limb0, &limb1) in x.transactions_root.iter().zip(&y.transactions_root) { - let limb_left = builder.select(connect_intra_roots, limb0, zero); - let limb_right = builder.select(connect_intra_roots, limb1, zero); - builder.connect(limb_left, limb_right); + builder.connect(limb0, limb1); } for (&limb0, &limb1) in x.receipts_root.iter().zip(&y.receipts_root) { - let limb_left = builder.select(connect_intra_roots, limb0, zero); - let limb_right = builder.select(connect_intra_roots, limb1, zero); - builder.connect(limb_left, limb_right); + builder.connect(limb0, limb1); } } -fn connect_state_roots, const D: usize>( +/// Connect block metadata across two consecutive proofs within a same block. +fn connect_block_metadata, const D: usize>( builder: &mut CircuitBuilder, - x: &TrieRootsTarget, - y: &TrieRootsTarget, + x: &BlockMetadataTarget, + y: &BlockMetadataTarget, ) where F: RichField + Extendable, { - for (limb0, limb1) in x.state_root.iter().zip(&y.state_root) { - builder.connect(*limb0, *limb1); + for (&limb0, &limb1) in x.block_beneficiary.iter().zip(&y.block_beneficiary) { + builder.connect(limb0, limb1); } + + builder.connect(x.block_timestamp, y.block_timestamp); + builder.connect(x.block_number, y.block_number); + builder.connect(x.block_difficulty, y.block_difficulty); + builder.connect(x.block_gaslimit, y.block_gaslimit); + builder.connect(x.block_chain_id, y.block_chain_id); + builder.connect(x.block_base_fee, y.block_base_fee); } /// The recursion threshold. We end a chain of recursive proofs once we reach this size. @@ -771,17 +720,8 @@ where &rhs.evm_proof.public_values, ); - let blocks_are_equal = builder.is_equal( - pv_lhs.block_metadata_pair.1.block_timestamp, - pv_rhs.block_metadata_pair.0.block_timestamp, - ); - - connect_trie_roots( - builder, - blocks_are_equal, - &pv_lhs.trie_roots_after, - &pv_rhs.trie_roots_before, - ); + connect_trie_roots(builder, &pv_lhs.trie_roots_after, &pv_rhs.trie_roots_before); + connect_block_metadata(builder, &pv_lhs.block_metadata, &pv_rhs.block_metadata); } fn connect_block_proof( @@ -789,60 +729,16 @@ where lhs: &EvmProofTarget, rhs: &EvmProofTarget, ) { - connect_state_roots( + connect_trie_roots( builder, &lhs.public_values.trie_roots_after, &rhs.public_values.trie_roots_before, ); - - const EMPTY_ROOT_HASH_LIMBS: [u32; 8] = [ - 0x171fe856, 0xa655cc1b, 0xe64583ff, 0x6ef8c092, 0x1be0485b, 0xc0ad6c99, 0xb52f6201, - 0x21b463e3, - ]; - - let empty_root: [Target; 8] = core::array::from_fn(|i| { - builder.constant(F::from_canonical_u32(EMPTY_ROOT_HASH_LIMBS[i])) - }); - - // Block proofs combine two entire blocks together, - // hence txn / receipt roots before should be empty. - for (limb1, limb2) in lhs - .public_values - .trie_roots_before - .transactions_root - .iter() - .zip(empty_root) - { - builder.connect(*limb1, limb2); - } - for (limb1, limb2) in lhs - .public_values - .trie_roots_before - .receipts_root - .iter() - .zip(empty_root) - { - builder.connect(*limb1, limb2); - } - - for (limb1, limb2) in rhs - .public_values - .trie_roots_before - .transactions_root - .iter() - .zip(empty_root) - { - builder.connect(*limb1, limb2); - } - for (limb1, limb2) in rhs - .public_values - .trie_roots_before - .receipts_root - .iter() - .zip(empty_root) - { - builder.connect(*limb1, limb2); - } + connect_block_metadata( + builder, + &lhs.public_values.block_metadata, + &rhs.public_values.block_metadata, + ); } fn create_block_circuit(agg: &AggregationCircuitData) -> BlockCircuitData { @@ -925,14 +821,7 @@ where Ok(EvmProof { proof: self.root.circuit.prove(root_inputs)?, - public_values: AggregatedPublicValues { - trie_roots_before: all_proof.public_values.trie_roots_before, - trie_roots_after: all_proof.public_values.trie_roots_after, - block_metadata_pair: ( - all_proof.public_values.block_metadata.clone(), - all_proof.public_values.block_metadata, - ), - }, + public_values: all_proof.public_values, }) } @@ -964,13 +853,11 @@ where Ok(EvmProof { proof: self.aggregation.circuit.prove(agg_inputs)?, - public_values: AggregatedPublicValues { + public_values: PublicValues { trie_roots_before: lhs_proof.public_values.trie_roots_before.clone(), trie_roots_after: rhs_proof.public_values.trie_roots_after.clone(), - block_metadata_pair: ( - lhs_proof.public_values.block_metadata_pair.0.clone(), - rhs_proof.public_values.block_metadata_pair.1.clone(), - ), + // Block metadata should be the same. + block_metadata: lhs_proof.public_values.block_metadata.clone(), }, }) } @@ -1011,10 +898,10 @@ where &self.block.circuit.verifier_only, HashMap::new(), ), - // We plug the aggregation_proof trie_roots_before - // to this proof trie_roots_after for valid connection + // We plug the `aggregation_proof`'s `trie_roots_before` + // to this proof `trie_roots_after` for valid connection // between proofs state tries. We do not care about the rest. - public_values: AggregatedPublicValues { + public_values: PublicValues { trie_roots_after: agg_root_proof.public_values.trie_roots_before.clone(), ..agg_root_proof.public_values.clone() }, @@ -1031,27 +918,17 @@ where block_inputs .set_verifier_data_target(&self.block.cyclic_vk, &self.block.circuit.verifier_only); - let (trie_roots_before, block_metadata_pair) = if let Some(bp) = opt_parent_block_proof { - ( - bp.public_values.trie_roots_before.clone(), - ( - bp.public_values.block_metadata_pair.0.clone(), - agg_root_proof.public_values.block_metadata_pair.1.clone(), - ), - ) + let trie_roots_before = if let Some(bp) = opt_parent_block_proof { + bp.public_values.trie_roots_before.clone() } else { - ( - agg_root_proof.public_values.trie_roots_before.clone(), - agg_root_proof.public_values.block_metadata_pair.clone(), - ) + agg_root_proof.public_values.trie_roots_before.clone() }; Ok(EvmProof { proof: self.block.circuit.prove(block_inputs)?, - public_values: AggregatedPublicValues { + public_values: PublicValues { trie_roots_before, - trie_roots_after: agg_root_proof.public_values.trie_roots_after.clone(), - block_metadata_pair, + ..agg_root_proof.public_values.clone() }, }) } diff --git a/evm/src/proof.rs b/evm/src/proof.rs index b11fe8271d..3c241ba0df 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -54,16 +54,6 @@ pub struct PublicValues { pub block_metadata: BlockMetadata, } -/// Memory values which are public over an aggregaton of blocks. -#[derive(Debug, Clone, Default)] -pub struct AggregatedPublicValues { - pub trie_roots_before: TrieRoots, - pub trie_roots_after: TrieRoots, - /// Represents the leftmost and rightmost block_metadata of the associated - /// aggregation proof, to allow combination on both sides with another proof. - pub block_metadata_pair: (BlockMetadata, BlockMetadata), -} - #[derive(Debug, Clone, Default)] pub struct TrieRoots { pub state_root: H256, @@ -84,29 +74,18 @@ pub struct BlockMetadata { /// Memory values which are public. /// Note: All the larger integers are encoded with 32-bit limbs in little-endian order. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct PublicValuesTarget { pub trie_roots_before: TrieRootsTarget, pub trie_roots_after: TrieRootsTarget, pub block_metadata: BlockMetadataTarget, } -/// Memory values which are public over an aggregaton of blocks. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct AggregatedPublicValuesTarget { - pub trie_roots_before: TrieRootsTarget, - pub trie_roots_after: TrieRootsTarget, - /// Represents the leftmost and rightmost block_metadata of the associated - /// aggregation proof, to allow combination on both sides with another proof. - pub block_metadata_pair: (BlockMetadataTarget, BlockMetadataTarget), -} - -impl AggregatedPublicValuesTarget { +impl PublicValuesTarget { pub fn to_buffer(&self, buffer: &mut Vec) -> IoResult<()> { self.trie_roots_before.to_buffer(buffer)?; self.trie_roots_after.to_buffer(buffer)?; - self.block_metadata_pair.0.to_buffer(buffer)?; - self.block_metadata_pair.1.to_buffer(buffer)?; + self.block_metadata.to_buffer(buffer)?; Ok(()) } @@ -114,15 +93,12 @@ impl AggregatedPublicValuesTarget { pub fn from_buffer(buffer: &mut Buffer) -> IoResult { let trie_roots_before = TrieRootsTarget::from_buffer(buffer)?; let trie_roots_after = TrieRootsTarget::from_buffer(buffer)?; - let block_metadata_pair = ( - BlockMetadataTarget::from_buffer(buffer)?, - BlockMetadataTarget::from_buffer(buffer)?, - ); + let block_metadata = BlockMetadataTarget::from_buffer(buffer)?; Ok(Self { trie_roots_before, trie_roots_after, - block_metadata_pair, + block_metadata, }) } } diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 5921cf8e10..a93ba5f647 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -33,9 +33,8 @@ use crate::permutation::{ PermutationCheckDataTarget, }; use crate::proof::{ - AggregatedPublicValues, AggregatedPublicValuesTarget, BlockMetadata, BlockMetadataTarget, - PublicValues, PublicValuesTarget, StarkOpeningSetTarget, StarkProof, - StarkProofChallengesTarget, StarkProofTarget, StarkProofWithMetadata, TrieRoots, + BlockMetadata, BlockMetadataTarget, PublicValues, PublicValuesTarget, StarkOpeningSetTarget, + StarkProof, StarkProofChallengesTarget, StarkProofTarget, StarkProofWithMetadata, TrieRoots, TrieRootsTarget, }; use crate::stark::Stark; @@ -499,23 +498,6 @@ fn eval_l_0_and_l_last_circuit, const D: usize>( ) } -pub(crate) fn add_virtual_aggregated_public_values, const D: usize>( - builder: &mut CircuitBuilder, -) -> AggregatedPublicValuesTarget { - let trie_roots_before = add_virtual_trie_roots(builder); - let trie_roots_after = add_virtual_trie_roots(builder); - let block_metadata_pair = ( - add_virtual_block_metadata(builder), - add_virtual_block_metadata(builder), - ); - AggregatedPublicValuesTarget { - trie_roots_before, - trie_roots_after, - block_metadata_pair, - } -} - -#[allow(unused)] // TODO: used later? pub(crate) fn add_virtual_public_values, const D: usize>( builder: &mut CircuitBuilder, ) -> PublicValuesTarget { @@ -640,37 +622,6 @@ pub(crate) fn set_stark_proof_target, W, const D: set_fri_proof_target(witness, &proof_target.opening_proof, &proof.opening_proof); } -pub(crate) fn set_aggregated_public_value_targets( - witness: &mut W, - public_values_target: &AggregatedPublicValuesTarget, - public_values: &AggregatedPublicValues, -) where - F: RichField + Extendable, - W: Witness, -{ - set_trie_roots_target( - witness, - &public_values_target.trie_roots_before, - &public_values.trie_roots_before, - ); - set_trie_roots_target( - witness, - &public_values_target.trie_roots_after, - &public_values.trie_roots_after, - ); - set_block_metadata_target( - witness, - &public_values_target.block_metadata_pair.0, - &public_values.block_metadata_pair.0, - ); - set_block_metadata_target( - witness, - &public_values_target.block_metadata_pair.1, - &public_values.block_metadata_pair.1, - ); -} - -#[allow(unused)] // TODO: used later? pub(crate) fn set_public_value_targets( witness: &mut W, public_values_target: &PublicValuesTarget, diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index f8166acfee..af2e454842 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -61,7 +61,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> { let all_circuits = AllRecursiveCircuits::::new( &all_stark, - &[9..18, 9..15, 9..15, 9..10, 9..12, 9..18], // Minimal ranges to prove an empty list + &[9..17, 9..15, 9..15, 9..10, 9..13, 9..19], // Minimal ranges to prove an empty list &config, ); @@ -124,9 +124,12 @@ fn test_empty_txn_list() -> anyhow::Result<()> { all_circuits.verify_root(root_proof.clone())?; - // We can duplicate the root_proof here because the state hasn't mutated. + // We can duplicate the proofs here because the state hasn't mutated. let agg_proof = all_circuits.prove_aggregation(false, &root_proof, false, &root_proof)?; - all_circuits.verify_aggregation(&agg_proof) + all_circuits.verify_aggregation(&agg_proof)?; + + let block_proof = all_circuits.prove_block(None, &agg_proof)?; + all_circuits.verify_block(&block_proof) } fn init_logger() {