From d6be2b987b0c103eed6ffe675fc7a9d8e4c6e85b Mon Sep 17 00:00:00 2001 From: Robin Salen <30937548+Nashtare@users.noreply.github.com> Date: Fri, 22 Sep 2023 09:19:13 -0400 Subject: [PATCH] Remove `generic_const_exprs` feature from EVM crate (#1246) * Remove const_generic_exprs feature from EVM crate * Get a generic impl of StarkFrame --- evm/src/arithmetic/arithmetic_stark.rs | 25 ++- evm/src/byte_packing/byte_packing_stark.rs | 122 +++++++------ evm/src/cpu/bootstrap_kernel.rs | 21 +-- evm/src/cpu/cpu_stark.rs | 43 +++-- evm/src/cross_table_lookup.rs | 20 ++- evm/src/evaluation_frame.rs | 47 +++++ evm/src/fixed_recursive_verifier.rs | 24 +-- evm/src/keccak/keccak_stark.rs | 178 ++++++++++--------- evm/src/keccak/round_flags.rs | 38 ++-- evm/src/keccak_sponge/keccak_sponge_stark.rs | 33 +++- evm/src/lib.rs | 3 +- evm/src/logic.rs | 18 +- evm/src/lookup.rs | 29 +-- evm/src/memory/memory_stark.rs | 90 +++++----- evm/src/permutation.rs | 15 +- evm/src/prover.rs | 68 ++----- evm/src/recursive_verifier.rs | 11 +- evm/src/stark.rs | 21 ++- evm/src/stark_testing.rs | 52 ++---- evm/src/vanishing_poly.rs | 6 +- evm/src/vars.rs | 19 -- evm/src/verifier.rs | 29 +-- 22 files changed, 465 insertions(+), 447 deletions(-) create mode 100644 evm/src/evaluation_frame.rs delete mode 100644 evm/src/vars.rs diff --git a/evm/src/arithmetic/arithmetic_stark.rs b/evm/src/arithmetic/arithmetic_stark.rs index 5441cf27..a6db1278 100644 --- a/evm/src/arithmetic/arithmetic_stark.rs +++ b/evm/src/arithmetic/arithmetic_stark.rs @@ -7,18 +7,20 @@ use plonky2::field::packed::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::util::transpose; use static_assertions::const_assert; +use super::columns::NUM_ARITH_COLUMNS; use crate::all_stark::Table; use crate::arithmetic::{addcy, byte, columns, divmod, modular, mul, Operation}; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cross_table_lookup::{Column, TableWithColumns}; +use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; use crate::lookup::{eval_lookups, eval_lookups_circuit, permuted_cols}; use crate::permutation::PermutationPair; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; /// Link the 16-bit columns of the arithmetic table, split into groups /// of N_LIMBS at a time in `regs`, with the corresponding 32-bit @@ -168,11 +170,16 @@ impl ArithmeticStark { } impl, const D: usize> Stark for ArithmeticStark { - const COLUMNS: usize = columns::NUM_ARITH_COLUMNS; + type EvaluationFrame = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, NUM_ARITH_COLUMNS>; fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, @@ -183,8 +190,8 @@ impl, const D: usize> Stark for ArithmeticSta eval_lookups(vars, yield_constr, col, col + 1); } - let lv = vars.local_values; - let nv = vars.next_values; + let lv: &[P; NUM_ARITH_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let nv: &[P; NUM_ARITH_COLUMNS] = vars.get_next_values().try_into().unwrap(); // Check the range column: First value must be 0, last row // must be 2^16-1, and intermediate rows must increment by 0 @@ -207,7 +214,7 @@ impl, const D: usize> Stark for ArithmeticSta fn eval_ext_circuit( &self, builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ) { // Range check all the columns @@ -215,8 +222,10 @@ impl, const D: usize> Stark for ArithmeticSta eval_lookups_circuit(builder, vars, yield_constr, col, col + 1); } - let lv = vars.local_values; - let nv = vars.next_values; + let lv: &[ExtensionTarget; NUM_ARITH_COLUMNS] = + vars.get_local_values().try_into().unwrap(); + let nv: &[ExtensionTarget; NUM_ARITH_COLUMNS] = + vars.get_next_values().try_into().unwrap(); let rc1 = lv[columns::RANGE_COUNTER]; let rc2 = nv[columns::RANGE_COUNTER]; diff --git a/evm/src/byte_packing/byte_packing_stark.rs b/evm/src/byte_packing/byte_packing_stark.rs index aa6a2dcf..d8f8e2e8 100644 --- a/evm/src/byte_packing/byte_packing_stark.rs +++ b/evm/src/byte_packing/byte_packing_stark.rs @@ -51,9 +51,9 @@ use crate::byte_packing::columns::{ }; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cross_table_lookup::Column; +use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; use crate::lookup::{eval_lookups, eval_lookups_circuit, permuted_cols}; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; use crate::witness::memory::MemoryAddress; /// Strict upper bound for the individual bytes range-check. @@ -211,7 +211,7 @@ impl, const D: usize> BytePackingStark { row[value_bytes(i)] = F::from_canonical_u8(byte); row[index_bytes(i)] = F::ONE; - rows.push(row.into()); + rows.push(row); row[index_bytes(i)] = F::ZERO; row[ADDR_VIRTUAL] -= F::ONE; } @@ -248,7 +248,7 @@ impl, const D: usize> BytePackingStark { } } - /// There is only one `i` for which `vars.local_values[index_bytes(i)]` is non-zero, + /// There is only one `i` for which `local_values[index_bytes(i)]` is non-zero, /// and `i+1` is the current position: fn get_active_position(&self, row: &[P; NUM_COLUMNS]) -> P where @@ -281,11 +281,16 @@ impl, const D: usize> BytePackingStark { } impl, const D: usize> Stark for BytePackingStark { - const COLUMNS: usize = NUM_COLUMNS; + type EvaluationFrame = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, NUM_COLUMNS>; fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, @@ -296,68 +301,62 @@ impl, const D: usize> Stark for BytePackingSt eval_lookups(vars, yield_constr, col, col + 1); } + let local_values: &[P; NUM_COLUMNS] = vars.get_local_values().try_into().unwrap(); + let next_values: &[P; NUM_COLUMNS] = vars.get_next_values().try_into().unwrap(); + let one = P::ONES; // We filter active columns by summing all the byte indices. // Constraining each of them to be boolean is done later on below. - let current_filter = vars.local_values[BYTE_INDICES_COLS] - .iter() - .copied() - .sum::

(); + let current_filter = local_values[BYTE_INDICES_COLS].iter().copied().sum::

(); yield_constr.constraint(current_filter * (current_filter - one)); // The filter column must start by one. yield_constr.constraint_first_row(current_filter - one); // The is_read flag must be boolean. - let current_is_read = vars.local_values[IS_READ]; + let current_is_read = local_values[IS_READ]; yield_constr.constraint(current_is_read * (current_is_read - one)); // Each byte index must be boolean. for i in 0..NUM_BYTES { - let idx_i = vars.local_values[index_bytes(i)]; + let idx_i = local_values[index_bytes(i)]; yield_constr.constraint(idx_i * (idx_i - one)); } // The sequence start flag column must start by one. - let current_sequence_start = vars.local_values[index_bytes(0)]; + let current_sequence_start = local_values[index_bytes(0)]; yield_constr.constraint_first_row(current_sequence_start - one); // The sequence end flag must be boolean - let current_sequence_end = vars.local_values[SEQUENCE_END]; + let current_sequence_end = local_values[SEQUENCE_END]; yield_constr.constraint(current_sequence_end * (current_sequence_end - one)); // If filter is off, all flags and byte indices must be off. - let byte_indices = vars.local_values[BYTE_INDICES_COLS] - .iter() - .copied() - .sum::

(); + let byte_indices = local_values[BYTE_INDICES_COLS].iter().copied().sum::

(); yield_constr.constraint( (current_filter - one) * (current_is_read + current_sequence_end + byte_indices), ); // Only padding rows have their filter turned off. - let next_filter = vars.next_values[BYTE_INDICES_COLS] - .iter() - .copied() - .sum::

(); + let next_filter = next_values[BYTE_INDICES_COLS].iter().copied().sum::

(); yield_constr.constraint_transition(next_filter * (next_filter - current_filter)); // Unless the current sequence end flag is activated, the is_read filter must remain unchanged. - let next_is_read = vars.next_values[IS_READ]; + let next_is_read = next_values[IS_READ]; yield_constr .constraint_transition((current_sequence_end - one) * (next_is_read - current_is_read)); // If the sequence end flag is activated, the next row must be a new sequence or filter must be off. - let next_sequence_start = vars.next_values[index_bytes(0)]; + let next_sequence_start = next_values[index_bytes(0)]; yield_constr.constraint_transition( current_sequence_end * next_filter * (next_sequence_start - one), ); // The active position in a byte sequence must increase by one on every row // or be one on the next row (i.e. at the start of a new sequence). - let current_position = self.get_active_position(vars.local_values); - let next_position = self.get_active_position(vars.next_values); + let current_position = self.get_active_position(local_values); + let next_position = self.get_active_position(next_values); yield_constr.constraint_transition( next_filter * (next_position - one) * (next_position - current_position - one), ); @@ -371,14 +370,14 @@ impl, const D: usize> Stark for BytePackingSt // The context, segment and timestamp fields must remain unchanged throughout a byte sequence. // The virtual address must decrement by one at each step of a sequence. - let current_context = vars.local_values[ADDR_CONTEXT]; - let next_context = vars.next_values[ADDR_CONTEXT]; - let current_segment = vars.local_values[ADDR_SEGMENT]; - let next_segment = vars.next_values[ADDR_SEGMENT]; - let current_virtual = vars.local_values[ADDR_VIRTUAL]; - let next_virtual = vars.next_values[ADDR_VIRTUAL]; - let current_timestamp = vars.local_values[TIMESTAMP]; - let next_timestamp = vars.next_values[TIMESTAMP]; + let current_context = local_values[ADDR_CONTEXT]; + let next_context = next_values[ADDR_CONTEXT]; + let current_segment = local_values[ADDR_SEGMENT]; + let next_segment = next_values[ADDR_SEGMENT]; + let current_virtual = local_values[ADDR_VIRTUAL]; + let next_virtual = next_values[ADDR_VIRTUAL]; + let current_timestamp = local_values[TIMESTAMP]; + let next_timestamp = next_values[TIMESTAMP]; yield_constr.constraint_transition( next_filter * (next_sequence_start - one) * (next_context - current_context), ); @@ -395,9 +394,9 @@ impl, const D: usize> Stark for BytePackingSt // If not at the end of a sequence, each next byte must equal the current one // when reading through the sequence, or the next byte index must be one. for i in 0..NUM_BYTES { - let current_byte = vars.local_values[value_bytes(i)]; - let next_byte = vars.next_values[value_bytes(i)]; - let next_byte_index = vars.next_values[index_bytes(i)]; + let current_byte = local_values[value_bytes(i)]; + let next_byte = next_values[value_bytes(i)]; + let next_byte_index = next_values[index_bytes(i)]; yield_constr.constraint_transition( (current_sequence_end - one) * (next_byte_index - one) * (next_byte - current_byte), ); @@ -407,7 +406,7 @@ impl, const D: usize> Stark for BytePackingSt fn eval_ext_circuit( &self, builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ) { // Range check all the columns @@ -415,9 +414,14 @@ impl, const D: usize> Stark for BytePackingSt eval_lookups_circuit(builder, vars, yield_constr, col, col + 1); } + let local_values: &[ExtensionTarget; NUM_COLUMNS] = + vars.get_local_values().try_into().unwrap(); + let next_values: &[ExtensionTarget; NUM_COLUMNS] = + vars.get_next_values().try_into().unwrap(); + // We filter active columns by summing all the byte indices. // Constraining each of them to be boolean is done later on below. - let current_filter = builder.add_many_extension(&vars.local_values[BYTE_INDICES_COLS]); + let current_filter = builder.add_many_extension(&local_values[BYTE_INDICES_COLS]); let constraint = builder.mul_sub_extension(current_filter, current_filter, current_filter); yield_constr.constraint(builder, constraint); @@ -426,25 +430,25 @@ impl, const D: usize> Stark for BytePackingSt yield_constr.constraint_first_row(builder, constraint); // The is_read flag must be boolean. - let current_is_read = vars.local_values[IS_READ]; + let current_is_read = local_values[IS_READ]; let constraint = builder.mul_sub_extension(current_is_read, current_is_read, current_is_read); yield_constr.constraint(builder, constraint); // Each byte index must be boolean. for i in 0..NUM_BYTES { - let idx_i = vars.local_values[index_bytes(i)]; + let idx_i = local_values[index_bytes(i)]; let constraint = builder.mul_sub_extension(idx_i, idx_i, idx_i); yield_constr.constraint(builder, constraint); } // The sequence start flag column must start by one. - let current_sequence_start = vars.local_values[index_bytes(0)]; + let current_sequence_start = local_values[index_bytes(0)]; let constraint = builder.add_const_extension(current_sequence_start, F::NEG_ONE); yield_constr.constraint_first_row(builder, constraint); // The sequence end flag must be boolean - let current_sequence_end = vars.local_values[SEQUENCE_END]; + let current_sequence_end = local_values[SEQUENCE_END]; let constraint = builder.mul_sub_extension( current_sequence_end, current_sequence_end, @@ -453,27 +457,27 @@ impl, const D: usize> Stark for BytePackingSt yield_constr.constraint(builder, constraint); // If filter is off, all flags and byte indices must be off. - let byte_indices = builder.add_many_extension(&vars.local_values[BYTE_INDICES_COLS]); + let byte_indices = builder.add_many_extension(&local_values[BYTE_INDICES_COLS]); let constraint = builder.add_extension(current_sequence_end, byte_indices); let constraint = builder.add_extension(constraint, current_is_read); let constraint = builder.mul_sub_extension(constraint, current_filter, constraint); yield_constr.constraint(builder, constraint); // Only padding rows have their filter turned off. - let next_filter = builder.add_many_extension(&vars.next_values[BYTE_INDICES_COLS]); + let next_filter = builder.add_many_extension(&next_values[BYTE_INDICES_COLS]); let constraint = builder.sub_extension(next_filter, current_filter); let constraint = builder.mul_extension(next_filter, constraint); yield_constr.constraint_transition(builder, constraint); // Unless the current sequence end flag is activated, the is_read filter must remain unchanged. - let next_is_read = vars.next_values[IS_READ]; + let next_is_read = next_values[IS_READ]; let diff_is_read = builder.sub_extension(next_is_read, current_is_read); let constraint = builder.mul_sub_extension(diff_is_read, current_sequence_end, diff_is_read); yield_constr.constraint_transition(builder, constraint); // If the sequence end flag is activated, the next row must be a new sequence or filter must be off. - let next_sequence_start = vars.next_values[index_bytes(0)]; + let next_sequence_start = next_values[index_bytes(0)]; let constraint = builder.mul_sub_extension( current_sequence_end, next_sequence_start, @@ -484,8 +488,8 @@ impl, const D: usize> Stark for BytePackingSt // The active position in a byte sequence must increase by one on every row // or be one on the next row (i.e. at the start of a new sequence). - let current_position = self.get_active_position_circuit(builder, vars.local_values); - let next_position = self.get_active_position_circuit(builder, vars.next_values); + let current_position = self.get_active_position_circuit(builder, local_values); + let next_position = self.get_active_position_circuit(builder, next_values); let position_diff = builder.sub_extension(next_position, current_position); let is_new_or_inactive = builder.mul_sub_extension(next_filter, next_position, next_filter); @@ -505,14 +509,14 @@ impl, const D: usize> Stark for BytePackingSt // The context, segment and timestamp fields must remain unchanged throughout a byte sequence. // The virtual address must decrement by one at each step of a sequence. - let current_context = vars.local_values[ADDR_CONTEXT]; - let next_context = vars.next_values[ADDR_CONTEXT]; - let current_segment = vars.local_values[ADDR_SEGMENT]; - let next_segment = vars.next_values[ADDR_SEGMENT]; - let current_virtual = vars.local_values[ADDR_VIRTUAL]; - let next_virtual = vars.next_values[ADDR_VIRTUAL]; - let current_timestamp = vars.local_values[TIMESTAMP]; - let next_timestamp = vars.next_values[TIMESTAMP]; + let current_context = local_values[ADDR_CONTEXT]; + let next_context = next_values[ADDR_CONTEXT]; + let current_segment = local_values[ADDR_SEGMENT]; + let next_segment = next_values[ADDR_SEGMENT]; + let current_virtual = local_values[ADDR_VIRTUAL]; + let next_virtual = next_values[ADDR_VIRTUAL]; + let current_timestamp = local_values[TIMESTAMP]; + let next_timestamp = next_values[TIMESTAMP]; let addr_filter = builder.mul_sub_extension(next_filter, next_sequence_start, next_filter); { let constraint = builder.sub_extension(next_context, current_context); @@ -538,9 +542,9 @@ impl, const D: usize> Stark for BytePackingSt // If not at the end of a sequence, each next byte must equal the current one // when reading through the sequence, or the next byte index must be one. for i in 0..NUM_BYTES { - let current_byte = vars.local_values[value_bytes(i)]; - let next_byte = vars.next_values[value_bytes(i)]; - let next_byte_index = vars.next_values[index_bytes(i)]; + let current_byte = local_values[value_bytes(i)]; + let next_byte = next_values[value_bytes(i)]; + let next_byte_index = next_values[index_bytes(i)]; let byte_diff = builder.sub_extension(next_byte, current_byte); let constraint = builder.mul_sub_extension(byte_diff, next_byte_index, byte_diff); let constraint = diff --git a/evm/src/cpu/bootstrap_kernel.rs b/evm/src/cpu/bootstrap_kernel.rs index 4aee617c..759c852a 100644 --- a/evm/src/cpu/bootstrap_kernel.rs +++ b/evm/src/cpu/bootstrap_kernel.rs @@ -1,22 +1,20 @@ //! The initial phase of execution, where the kernel code is hashed while being written to memory. //! The hash is then checked against a precomputed kernel hash. -use std::borrow::Borrow; - use itertools::Itertools; use plonky2::field::extension::Extendable; use plonky2::field::packed::PackedField; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::plonk::circuit_builder::CircuitBuilder; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; -use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS}; +use crate::cpu::columns::CpuColumnsView; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::membus::NUM_GP_CHANNELS; use crate::generation::state::GenerationState; use crate::memory::segments::Segment; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; use crate::witness::memory::MemoryAddress; use crate::witness::util::{keccak_sponge_log, mem_write_gp_log_and_fill}; @@ -58,13 +56,11 @@ pub(crate) fn generate_bootstrap_kernel(state: &mut GenerationState log::info!("Bootstrapping took {} cycles", state.traces.clock()); } -pub(crate) fn eval_bootstrap_kernel>( - vars: StarkEvaluationVars, +pub(crate) fn eval_bootstrap_kernel_packed>( + local_values: &CpuColumnsView

, + next_values: &CpuColumnsView

, yield_constr: &mut ConstraintConsumer

, ) { - let local_values: &CpuColumnsView<_> = vars.local_values.borrow(); - let next_values: &CpuColumnsView<_> = vars.next_values.borrow(); - // IS_BOOTSTRAP_KERNEL must have an init value of 1, a final value of 0, and a delta in {0, -1}. let local_is_bootstrap = local_values.is_bootstrap_kernel; let next_is_bootstrap = next_values.is_bootstrap_kernel; @@ -103,13 +99,12 @@ pub(crate) fn eval_bootstrap_kernel>( } } -pub(crate) fn eval_bootstrap_kernel_circuit, const D: usize>( +pub(crate) fn eval_bootstrap_kernel_ext_circuit, const D: usize>( builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, + local_values: &CpuColumnsView>, + next_values: &CpuColumnsView>, yield_constr: &mut RecursiveConstraintConsumer, ) { - let local_values: &CpuColumnsView<_> = vars.local_values.borrow(); - let next_values: &CpuColumnsView<_> = vars.next_values.borrow(); let one = builder.one_extension(); // IS_BOOTSTRAP_KERNEL must have an init value of 1, a final value of 0, and a delta in {0, -1}. diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index bd2fcf19..14bb6015 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -7,6 +7,7 @@ use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::packed::PackedField; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use super::halt; use crate::all_stark::Table; @@ -18,10 +19,10 @@ use crate::cpu::{ modfp254, pc, push0, shift, simple_logic, stack, stack_bounds, syscalls_exceptions, }; use crate::cross_table_lookup::{Column, TableWithColumns}; +use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; use crate::memory::segments::Segment; use crate::memory::{NUM_CHANNELS, VALUE_LIMBS}; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; pub fn ctl_data_keccak_sponge() -> Vec> { // When executing KECCAK_GENERAL, the GP memory channels are used as follows: @@ -227,19 +228,29 @@ impl CpuStark { } impl, const D: usize> Stark for CpuStark { - const COLUMNS: usize = NUM_CPU_COLUMNS; + type EvaluationFrame = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, NUM_CPU_COLUMNS>; fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, P: PackedField, { - let local_values = vars.local_values.borrow(); - let next_values = vars.next_values.borrow(); - bootstrap_kernel::eval_bootstrap_kernel(vars, yield_constr); + let local_values = + TryInto::<[P; NUM_CPU_COLUMNS]>::try_into(vars.get_local_values()).unwrap(); + let local_values: &CpuColumnsView

= local_values.borrow(); + let next_values = + TryInto::<[P; NUM_CPU_COLUMNS]>::try_into(vars.get_next_values()).unwrap(); + let next_values: &CpuColumnsView

= next_values.borrow(); + + bootstrap_kernel::eval_bootstrap_kernel_packed(local_values, next_values, yield_constr); contextops::eval_packed(local_values, next_values, yield_constr); control_flow::eval_packed_generic(local_values, next_values, yield_constr); decode::eval_packed_generic(local_values, yield_constr); @@ -262,12 +273,24 @@ impl, const D: usize> Stark for CpuStark, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ) { - let local_values = vars.local_values.borrow(); - let next_values = vars.next_values.borrow(); - bootstrap_kernel::eval_bootstrap_kernel_circuit(builder, vars, yield_constr); + let local_values = + TryInto::<[ExtensionTarget; NUM_CPU_COLUMNS]>::try_into(vars.get_local_values()) + .unwrap(); + let local_values: &CpuColumnsView> = local_values.borrow(); + let next_values = + TryInto::<[ExtensionTarget; NUM_CPU_COLUMNS]>::try_into(vars.get_next_values()) + .unwrap(); + let next_values: &CpuColumnsView> = next_values.borrow(); + + bootstrap_kernel::eval_bootstrap_kernel_ext_circuit( + builder, + local_values, + next_values, + yield_constr, + ); contextops::eval_ext_circuit(builder, local_values, next_values, yield_constr); control_flow::eval_ext_circuit(builder, local_values, next_values, yield_constr); decode::eval_ext_circuit(builder, local_values, yield_constr); diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index a2dad1ab..28b18994 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -16,10 +16,10 @@ use plonky2::plonk::config::GenericConfig; use crate::all_stark::{Table, NUM_TABLES}; use crate::config::StarkConfig; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use crate::evaluation_frame::StarkEvaluationFrame; use crate::permutation::{GrandProductChallenge, GrandProductChallengeSet}; use crate::proof::{StarkProofTarget, StarkProofWithMetadata}; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; /// Represent a linear combination of columns. #[derive(Clone, Debug)] @@ -473,7 +473,7 @@ impl<'a, F: RichField + Extendable, const D: usize> /// Z(w) = Z(gw) * combine(w) where combine is called on the local row /// and not the next. This enables CTLs across two rows. pub(crate) fn eval_cross_table_lookup_checks( - vars: StarkEvaluationVars, + vars: &S::EvaluationFrame, ctl_vars: &[CtlCheckVars], consumer: &mut ConstraintConsumer

, ) where @@ -482,6 +482,9 @@ pub(crate) fn eval_cross_table_lookup_checks, S: Stark, { + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); + for lookup_vars in ctl_vars { let CtlCheckVars { local_z, @@ -493,11 +496,11 @@ pub(crate) fn eval_cross_table_lookup_checks>(); let combined = challenges.combine(evals.iter()); let local_filter = if let Some(column) = filter_column { - column.eval_with_next(vars.local_values, vars.next_values) + column.eval_with_next(local_values, next_values) } else { P::ONES }; @@ -580,10 +583,13 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< const D: usize, >( builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, + vars: &S::EvaluationFrameTarget, ctl_vars: &[CtlCheckVarsTarget], consumer: &mut RecursiveConstraintConsumer, ) { + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); + for lookup_vars in ctl_vars { let CtlCheckVarsTarget { local_z, @@ -595,7 +601,7 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< let one = builder.one_extension(); let local_filter = if let Some(column) = filter_column { - column.eval_circuit(builder, vars.local_values) + column.eval_circuit(builder, local_values) } else { one }; @@ -611,7 +617,7 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< let evals = columns .iter() - .map(|c| c.eval_with_next_circuit(builder, vars.local_values, vars.next_values)) + .map(|c| c.eval_with_next_circuit(builder, local_values, next_values)) .collect::>(); let combined = challenges.combine_circuit(builder, &evals); diff --git a/evm/src/evaluation_frame.rs b/evm/src/evaluation_frame.rs new file mode 100644 index 00000000..0f6bbe2c --- /dev/null +++ b/evm/src/evaluation_frame.rs @@ -0,0 +1,47 @@ +/// A trait for viewing an evaluation frame of a STARK table. +/// +/// It allows to access the current and next rows at a given step +/// and can be used to implement constraint evaluation both natively +/// and recursively. +pub trait StarkEvaluationFrame: Sized { + /// The number of columns for the STARK table this evaluation frame views. + const COLUMNS: usize; + + /// Returns the local values (i.e. current row) for this evaluation frame. + fn get_local_values(&self) -> &[T]; + /// Returns the next values (i.e. next row) for this evaluation frame. + fn get_next_values(&self) -> &[T]; + + /// Outputs a new evaluation frame from the provided local and next values. + /// + /// **NOTE**: Concrete implementations of this method SHOULD ensure that + /// the provided slices lengths match the `Self::COLUMNS` value. + fn from_values(lv: &[T], nv: &[T]) -> Self; +} + +pub struct StarkFrame { + local_values: [T; N], + next_values: [T; N], +} + +impl StarkEvaluationFrame for StarkFrame { + const COLUMNS: usize = N; + + fn get_local_values(&self) -> &[T] { + &self.local_values + } + + fn get_next_values(&self) -> &[T] { + &self.next_values + } + + fn from_values(lv: &[T], nv: &[T]) -> Self { + assert_eq!(lv.len(), Self::COLUMNS); + assert_eq!(nv.len(), Self::COLUMNS); + + Self { + local_values: lv.try_into().unwrap(), + next_values: nv.try_into().unwrap(), + } + } +} diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index 05ec015c..7fefe95f 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -28,17 +28,10 @@ use plonky2::util::timing::TimingTree; use plonky2_util::log2_ceil; use crate::all_stark::{all_cross_table_lookups, AllStark, Table, NUM_TABLES}; -use crate::arithmetic::arithmetic_stark::ArithmeticStark; -use crate::byte_packing::byte_packing_stark::BytePackingStark; use crate::config::StarkConfig; -use crate::cpu::cpu_stark::CpuStark; use crate::cross_table_lookup::{verify_cross_table_lookups_circuit, CrossTableLookup}; use crate::generation::GenerationInputs; use crate::get_challenges::observe_public_values_target; -use crate::keccak::keccak_stark::KeccakStark; -use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeStark; -use crate::logic::LogicStark; -use crate::memory::memory_stark::MemoryStark; use crate::permutation::{get_grand_product_challenge_set_target, GrandProductChallengeSet}; use crate::proof::{ BlockHashesTarget, BlockMetadataTarget, ExtraBlockDataTarget, PublicValues, PublicValuesTarget, @@ -297,13 +290,6 @@ where F: RichField + Extendable, C: GenericConfig + 'static, C::Hasher: AlgebraicHasher, - [(); ArithmeticStark::::COLUMNS]:, - [(); BytePackingStark::::COLUMNS]:, - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakSpongeStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, { pub fn to_bytes( &self, @@ -1083,10 +1069,7 @@ where degree_bits_range: Range, all_ctls: &[CrossTableLookup], stark_config: &StarkConfig, - ) -> Self - where - [(); S::COLUMNS]:, - { + ) -> Self { let by_stark_size = degree_bits_range .map(|degree_bits| { ( @@ -1207,10 +1190,7 @@ where degree_bits: usize, all_ctls: &[CrossTableLookup], stark_config: &StarkConfig, - ) -> Self - where - [(); S::COLUMNS]:, - { + ) -> Self { let initial_wrapper = recursive_stark_circuit( table, stark, diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index 74f92622..c517a5f6 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -6,12 +6,14 @@ use plonky2::field::packed::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::plonk::plonk_common::reduce_with_powers_ext_circuit; use plonky2::timed; use plonky2::util::timing::TimingTree; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cross_table_lookup::Column; +use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; use crate::keccak::columns::{ reg_a, reg_a_prime, reg_a_prime_prime, reg_a_prime_prime_0_0_bit, reg_a_prime_prime_prime, reg_b, reg_c, reg_c_prime, reg_input_limb, reg_output_limb, reg_preimage, reg_step, @@ -24,7 +26,6 @@ use crate::keccak::logic::{ use crate::keccak::round_flags::{eval_round_flags, eval_round_flags_recursively}; use crate::stark::Stark; use crate::util::trace_rows_to_poly_values; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; /// Number of rounds in a Keccak permutation. pub(crate) const NUM_ROUNDS: usize = 24; @@ -239,11 +240,16 @@ impl, const D: usize> KeccakStark { } impl, const D: usize> Stark for KeccakStark { - const COLUMNS: usize = NUM_COLUMNS; + type EvaluationFrame = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, NUM_COLUMNS>; fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, @@ -251,33 +257,34 @@ impl, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ) { let one_ext = builder.one_extension(); @@ -433,49 +440,44 @@ impl, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark, const D: usize> Stark for KeccakStark>( - vars: StarkEvaluationVars, + vars: &StarkFrame, yield_constr: &mut ConstraintConsumer

, ) { + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); + // Initially, the first step flag should be 1 while the others should be 0. - yield_constr.constraint_first_row(vars.local_values[reg_step(0)] - F::ONE); + yield_constr.constraint_first_row(local_values[reg_step(0)] - F::ONE); for i in 1..NUM_ROUNDS { - yield_constr.constraint_first_row(vars.local_values[reg_step(i)]); + yield_constr.constraint_first_row(local_values[reg_step(i)]); } // Flags should circularly increment, or be all zero for padding rows. - let next_any_flag = (0..NUM_ROUNDS) - .map(|i| vars.next_values[reg_step(i)]) - .sum::

(); + let next_any_flag = (0..NUM_ROUNDS).map(|i| next_values[reg_step(i)]).sum::

(); for i in 0..NUM_ROUNDS { - let current_round_flag = vars.local_values[reg_step(i)]; - let next_round_flag = vars.next_values[reg_step((i + 1) % NUM_ROUNDS)]; + let current_round_flag = local_values[reg_step(i)]; + let next_round_flag = next_values[reg_step((i + 1) % NUM_ROUNDS)]; yield_constr.constraint_transition(next_any_flag * (next_round_flag - current_round_flag)); } // Padding rows should always be followed by padding rows. let current_any_flag = (0..NUM_ROUNDS) - .map(|i| vars.local_values[reg_step(i)]) + .map(|i| local_values[reg_step(i)]) .sum::

(); yield_constr.constraint_transition(next_any_flag * (current_any_flag - F::ONE)); } pub(crate) fn eval_round_flags_recursively, const D: usize>( builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, + vars: &StarkFrame, NUM_COLUMNS>, yield_constr: &mut RecursiveConstraintConsumer, ) { let one = builder.one_extension(); + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); // Initially, the first step flag should be 1 while the others should be 0. - let step_0_minus_1 = builder.sub_extension(vars.local_values[reg_step(0)], one); + let step_0_minus_1 = builder.sub_extension(local_values[reg_step(0)], one); yield_constr.constraint_first_row(builder, step_0_minus_1); for i in 1..NUM_ROUNDS { - yield_constr.constraint_first_row(builder, vars.local_values[reg_step(i)]); + yield_constr.constraint_first_row(builder, local_values[reg_step(i)]); } // Flags should circularly increment, or be all zero for padding rows. let next_any_flag = - builder.add_many_extension((0..NUM_ROUNDS).map(|i| vars.next_values[reg_step(i)])); + builder.add_many_extension((0..NUM_ROUNDS).map(|i| next_values[reg_step(i)])); for i in 0..NUM_ROUNDS { - let current_round_flag = vars.local_values[reg_step(i)]; - let next_round_flag = vars.next_values[reg_step((i + 1) % NUM_ROUNDS)]; + let current_round_flag = local_values[reg_step(i)]; + let next_round_flag = next_values[reg_step((i + 1) % NUM_ROUNDS)]; let diff = builder.sub_extension(next_round_flag, current_round_flag); let constraint = builder.mul_extension(next_any_flag, diff); yield_constr.constraint_transition(builder, constraint); @@ -63,7 +67,7 @@ pub(crate) fn eval_round_flags_recursively, const D // Padding rows should always be followed by padding rows. let current_any_flag = - builder.add_many_extension((0..NUM_ROUNDS).map(|i| vars.local_values[reg_step(i)])); + builder.add_many_extension((0..NUM_ROUNDS).map(|i| local_values[reg_step(i)])); let constraint = builder.mul_sub_extension(next_any_flag, current_any_flag, next_any_flag); yield_constr.constraint_transition(builder, constraint); } diff --git a/evm/src/keccak_sponge/keccak_sponge_stark.rs b/evm/src/keccak_sponge/keccak_sponge_stark.rs index d78e9651..65edc941 100644 --- a/evm/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm/src/keccak_sponge/keccak_sponge_stark.rs @@ -17,10 +17,10 @@ use plonky2_util::ceil_div_usize; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cpu::kernel::keccak_util::keccakf_u32s; use crate::cross_table_lookup::Column; +use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; use crate::keccak_sponge::columns::*; use crate::stark::Stark; use crate::util::trace_rows_to_poly_values; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; use crate::witness::memory::MemoryAddress; pub(crate) fn ctl_looked_data() -> Vec> { @@ -423,18 +423,27 @@ impl, const D: usize> KeccakSpongeStark { } impl, const D: usize> Stark for KeccakSpongeStark { - const COLUMNS: usize = NUM_KECCAK_SPONGE_COLUMNS; + type EvaluationFrame = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, NUM_KECCAK_SPONGE_COLUMNS>; fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, P: PackedField, { - let local_values: &KeccakSpongeColumnsView

= vars.local_values.borrow(); - let next_values: &KeccakSpongeColumnsView

= vars.next_values.borrow(); + let local_values = + TryInto::<[P; NUM_KECCAK_SPONGE_COLUMNS]>::try_into(vars.get_local_values()).unwrap(); + let local_values: &KeccakSpongeColumnsView

= local_values.borrow(); + let next_values = + TryInto::<[P; NUM_KECCAK_SPONGE_COLUMNS]>::try_into(vars.get_next_values()).unwrap(); + let next_values: &KeccakSpongeColumnsView

= next_values.borrow(); // Each flag (full-input block, final block or implied dummy flag) must be boolean. let is_full_input_block = local_values.is_full_input_block; @@ -537,11 +546,19 @@ impl, const D: usize> Stark for KeccakSpongeS fn eval_ext_circuit( &self, builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ) { - let local_values: &KeccakSpongeColumnsView> = vars.local_values.borrow(); - let next_values: &KeccakSpongeColumnsView> = vars.next_values.borrow(); + let local_values = TryInto::<[ExtensionTarget; NUM_KECCAK_SPONGE_COLUMNS]>::try_into( + vars.get_local_values(), + ) + .unwrap(); + let local_values: &KeccakSpongeColumnsView> = local_values.borrow(); + let next_values = TryInto::<[ExtensionTarget; NUM_KECCAK_SPONGE_COLUMNS]>::try_into( + vars.get_next_values(), + ) + .unwrap(); + let next_values: &KeccakSpongeColumnsView> = next_values.borrow(); let one = builder.one_extension(); diff --git a/evm/src/lib.rs b/evm/src/lib.rs index ab48cda0..474d6faf 100644 --- a/evm/src/lib.rs +++ b/evm/src/lib.rs @@ -4,7 +4,6 @@ #![allow(clippy::type_complexity)] #![allow(clippy::field_reassign_with_default)] #![feature(let_chains)] -#![feature(generic_const_exprs)] pub mod all_stark; pub mod arithmetic; @@ -14,6 +13,7 @@ pub mod constraint_consumer; pub mod cpu; pub mod cross_table_lookup; pub mod curve_pairings; +pub mod evaluation_frame; pub mod extension_tower; pub mod fixed_recursive_verifier; pub mod generation; @@ -31,7 +31,6 @@ pub mod stark; pub mod stark_testing; pub mod util; pub mod vanishing_poly; -pub mod vars; pub mod verifier; pub mod witness; diff --git a/evm/src/logic.rs b/evm/src/logic.rs index 3529ed9a..319dfab2 100644 --- a/evm/src/logic.rs +++ b/evm/src/logic.rs @@ -7,16 +7,17 @@ use plonky2::field::packed::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::timed; use plonky2::util::timing::TimingTree; use plonky2_util::ceil_div_usize; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cross_table_lookup::Column; +use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; use crate::logic::columns::NUM_COLUMNS; use crate::stark::Stark; use crate::util::{limb_from_bits_le, limb_from_bits_le_recursive, trace_rows_to_poly_values}; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; // Total number of bits per input/output. const VAL_BITS: usize = 256; @@ -181,17 +182,22 @@ impl LogicStark { } impl, const D: usize> Stark for LogicStark { - const COLUMNS: usize = NUM_COLUMNS; + type EvaluationFrame = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, NUM_COLUMNS>; fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, P: PackedField, { - let lv = &vars.local_values; + let lv = vars.get_local_values(); // IS_AND, IS_OR, and IS_XOR come from the CPU table, so we assume they're valid. let is_and = lv[columns::IS_AND]; @@ -237,10 +243,10 @@ impl, const D: usize> Stark for LogicStark, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ) { - let lv = &vars.local_values; + let lv = vars.get_local_values(); // IS_AND, IS_OR, and IS_XOR come from the CPU table, so we assume they're valid. let is_and = lv[columns::IS_AND]; diff --git a/evm/src/lookup.rs b/evm/src/lookup.rs index d7e12bac..d6c1b217 100644 --- a/evm/src/lookup.rs +++ b/evm/src/lookup.rs @@ -5,20 +5,24 @@ use plonky2::field::extension::Extendable; use plonky2::field::packed::PackedField; use plonky2::field::types::{Field, PrimeField64}; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::plonk::circuit_builder::CircuitBuilder; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; +use crate::evaluation_frame::StarkEvaluationFrame; -pub(crate) fn eval_lookups, const COLS: usize>( - vars: StarkEvaluationVars, +pub(crate) fn eval_lookups, E: StarkEvaluationFrame

>( + vars: &E, yield_constr: &mut ConstraintConsumer

, col_permuted_input: usize, col_permuted_table: usize, ) { - let local_perm_input = vars.local_values[col_permuted_input]; - let next_perm_table = vars.next_values[col_permuted_table]; - let next_perm_input = vars.next_values[col_permuted_input]; + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); + + let local_perm_input = local_values[col_permuted_input]; + let next_perm_table = next_values[col_permuted_table]; + let next_perm_input = next_values[col_permuted_input]; // A "vertical" diff between the local and next permuted inputs. let diff_input_prev = next_perm_input - local_perm_input; @@ -35,18 +39,21 @@ pub(crate) fn eval_lookups, const COLS: usi pub(crate) fn eval_lookups_circuit< F: RichField + Extendable, + E: StarkEvaluationFrame>, const D: usize, - const COLS: usize, >( builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, + vars: &E, yield_constr: &mut RecursiveConstraintConsumer, col_permuted_input: usize, col_permuted_table: usize, ) { - let local_perm_input = vars.local_values[col_permuted_input]; - let next_perm_table = vars.next_values[col_permuted_table]; - let next_perm_input = vars.next_values[col_permuted_input]; + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); + + let local_perm_input = local_values[col_permuted_input]; + let next_perm_table = next_values[col_permuted_table]; + let next_perm_input = next_values[col_permuted_input]; // A "vertical" diff between the local and next permuted inputs. let diff_input_prev = builder.sub_extension(next_perm_input, local_perm_input); diff --git a/evm/src/memory/memory_stark.rs b/evm/src/memory/memory_stark.rs index 36f75665..fde93be0 100644 --- a/evm/src/memory/memory_stark.rs +++ b/evm/src/memory/memory_stark.rs @@ -7,6 +7,7 @@ use plonky2::field::packed::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::timed; use plonky2::util::timing::TimingTree; use plonky2::util::transpose; @@ -14,6 +15,7 @@ use plonky2_maybe_rayon::*; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cross_table_lookup::Column; +use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; use crate::lookup::{eval_lookups, eval_lookups_circuit, permuted_cols}; use crate::memory::columns::{ value_limb, ADDR_CONTEXT, ADDR_SEGMENT, ADDR_VIRTUAL, CONTEXT_FIRST_CHANGE, COUNTER, @@ -23,7 +25,6 @@ use crate::memory::columns::{ use crate::memory::VALUE_LIMBS; use crate::permutation::PermutationPair; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; use crate::witness::memory::MemoryOpKind::Read; use crate::witness::memory::{MemoryAddress, MemoryOp}; @@ -238,48 +239,55 @@ impl, const D: usize> MemoryStark { } impl, const D: usize> Stark for MemoryStark { - const COLUMNS: usize = NUM_COLUMNS; + type EvaluationFrame = StarkFrame + where + FE: FieldExtension, + P: PackedField; + + type EvaluationFrameTarget = StarkFrame, NUM_COLUMNS>; fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, P: PackedField, { let one = P::from(FE::ONE); + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); - let timestamp = vars.local_values[TIMESTAMP]; - let addr_context = vars.local_values[ADDR_CONTEXT]; - let addr_segment = vars.local_values[ADDR_SEGMENT]; - let addr_virtual = vars.local_values[ADDR_VIRTUAL]; - let values: Vec<_> = (0..8).map(|i| vars.local_values[value_limb(i)]).collect(); + let timestamp = local_values[TIMESTAMP]; + let addr_context = local_values[ADDR_CONTEXT]; + let addr_segment = local_values[ADDR_SEGMENT]; + let addr_virtual = local_values[ADDR_VIRTUAL]; + let value_limbs: Vec<_> = (0..8).map(|i| local_values[value_limb(i)]).collect(); - let next_timestamp = vars.next_values[TIMESTAMP]; - let next_is_read = vars.next_values[IS_READ]; - let next_addr_context = vars.next_values[ADDR_CONTEXT]; - let next_addr_segment = vars.next_values[ADDR_SEGMENT]; - let next_addr_virtual = vars.next_values[ADDR_VIRTUAL]; - let next_values: Vec<_> = (0..8).map(|i| vars.next_values[value_limb(i)]).collect(); + let next_timestamp = next_values[TIMESTAMP]; + let next_is_read = next_values[IS_READ]; + let next_addr_context = next_values[ADDR_CONTEXT]; + let next_addr_segment = next_values[ADDR_SEGMENT]; + let next_addr_virtual = next_values[ADDR_VIRTUAL]; + let next_values_limbs: Vec<_> = (0..8).map(|i| next_values[value_limb(i)]).collect(); // The filter must be 0 or 1. - let filter = vars.local_values[FILTER]; + let filter = local_values[FILTER]; yield_constr.constraint(filter * (filter - P::ONES)); // If this is a dummy row (filter is off), it must be a read. This means the prover can // insert reads which never appear in the CPU trace (which are harmless), but not writes. let is_dummy = P::ONES - filter; - let is_write = P::ONES - vars.local_values[IS_READ]; + let is_write = P::ONES - local_values[IS_READ]; yield_constr.constraint(is_dummy * is_write); - let context_first_change = vars.local_values[CONTEXT_FIRST_CHANGE]; - let segment_first_change = vars.local_values[SEGMENT_FIRST_CHANGE]; - let virtual_first_change = vars.local_values[VIRTUAL_FIRST_CHANGE]; + let context_first_change = local_values[CONTEXT_FIRST_CHANGE]; + let segment_first_change = local_values[SEGMENT_FIRST_CHANGE]; + let virtual_first_change = local_values[VIRTUAL_FIRST_CHANGE]; let address_unchanged = one - context_first_change - segment_first_change - virtual_first_change; - let range_check = vars.local_values[RANGE_CHECK]; + let range_check = local_values[RANGE_CHECK]; let not_context_first_change = one - context_first_change; let not_segment_first_change = one - segment_first_change; @@ -313,7 +321,7 @@ impl, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ) { let one = builder.one_extension(); + let local_values = vars.get_local_values(); + let next_values = vars.get_next_values(); - let addr_context = vars.local_values[ADDR_CONTEXT]; - let addr_segment = vars.local_values[ADDR_SEGMENT]; - let addr_virtual = vars.local_values[ADDR_VIRTUAL]; - let values: Vec<_> = (0..8).map(|i| vars.local_values[value_limb(i)]).collect(); - let timestamp = vars.local_values[TIMESTAMP]; + let addr_context = local_values[ADDR_CONTEXT]; + let addr_segment = local_values[ADDR_SEGMENT]; + let addr_virtual = local_values[ADDR_VIRTUAL]; + let value_limbs: Vec<_> = (0..8).map(|i| local_values[value_limb(i)]).collect(); + let timestamp = local_values[TIMESTAMP]; - let next_addr_context = vars.next_values[ADDR_CONTEXT]; - let next_addr_segment = vars.next_values[ADDR_SEGMENT]; - let next_addr_virtual = vars.next_values[ADDR_VIRTUAL]; - let next_values: Vec<_> = (0..8).map(|i| vars.next_values[value_limb(i)]).collect(); - let next_is_read = vars.next_values[IS_READ]; - let next_timestamp = vars.next_values[TIMESTAMP]; + let next_addr_context = next_values[ADDR_CONTEXT]; + let next_addr_segment = next_values[ADDR_SEGMENT]; + let next_addr_virtual = next_values[ADDR_VIRTUAL]; + let next_values_limbs: Vec<_> = (0..8).map(|i| next_values[value_limb(i)]).collect(); + let next_is_read = next_values[IS_READ]; + let next_timestamp = next_values[TIMESTAMP]; // The filter must be 0 or 1. - let filter = vars.local_values[FILTER]; + let filter = local_values[FILTER]; let constraint = builder.mul_sub_extension(filter, filter, filter); yield_constr.constraint(builder, constraint); // If this is a dummy row (filter is off), it must be a read. This means the prover can // insert reads which never appear in the CPU trace (which are harmless), but not writes. let is_dummy = builder.sub_extension(one, filter); - let is_write = builder.sub_extension(one, vars.local_values[IS_READ]); + let is_write = builder.sub_extension(one, local_values[IS_READ]); let is_dummy_write = builder.mul_extension(is_dummy, is_write); yield_constr.constraint(builder, is_dummy_write); - let context_first_change = vars.local_values[CONTEXT_FIRST_CHANGE]; - let segment_first_change = vars.local_values[SEGMENT_FIRST_CHANGE]; - let virtual_first_change = vars.local_values[VIRTUAL_FIRST_CHANGE]; + let context_first_change = local_values[CONTEXT_FIRST_CHANGE]; + let segment_first_change = local_values[SEGMENT_FIRST_CHANGE]; + let virtual_first_change = local_values[VIRTUAL_FIRST_CHANGE]; let address_unchanged = { let mut cur = builder.sub_extension(one, context_first_change); cur = builder.sub_extension(cur, segment_first_change); builder.sub_extension(cur, virtual_first_change) }; - let range_check = vars.local_values[RANGE_CHECK]; + let range_check = local_values[RANGE_CHECK]; let not_context_first_change = builder.sub_extension(one, context_first_change); let not_segment_first_change = builder.sub_extension(one, segment_first_change); @@ -433,7 +443,7 @@ impl, const D: usize> Stark for MemoryStark( stark: &S, config: &StarkConfig, - vars: StarkEvaluationVars, + vars: &S::EvaluationFrame, permutation_vars: PermutationCheckVars, consumer: &mut ConstraintConsumer

, ) where @@ -335,6 +335,8 @@ pub(crate) fn eval_permutation_checks, S: Stark, { + let local_values = vars.get_local_values(); + let PermutationCheckVars { local_zs, next_zs, @@ -368,7 +370,7 @@ pub(crate) fn eval_permutation_checks, Vec<_>) = column_pairs .iter() - .map(|&(i, j)| (vars.local_values[i], vars.local_values[j])) + .map(|&(i, j)| (local_values[i], local_values[j])) .unzip(); ( factor.reduce_ext(lhs.into_iter()) + FE::from_basefield(*gamma), @@ -392,14 +394,15 @@ pub(crate) fn eval_permutation_checks_circuit( builder: &mut CircuitBuilder, stark: &S, config: &StarkConfig, - vars: StarkEvaluationTargets, + vars: &S::EvaluationFrameTarget, permutation_data: PermutationCheckDataTarget, consumer: &mut RecursiveConstraintConsumer, ) where F: RichField + Extendable, S: Stark, - [(); S::COLUMNS]:, { + let local_values = vars.get_local_values(); + let PermutationCheckDataTarget { local_zs, next_zs, @@ -437,7 +440,7 @@ pub(crate) fn eval_permutation_checks_circuit( let mut factor = ReducingFactorTarget::new(beta_ext); let (lhs, rhs): (Vec<_>, Vec<_>) = column_pairs .iter() - .map(|&(i, j)| (vars.local_values[i], vars.local_values[j])) + .map(|&(i, j)| (local_values[i], local_values[j])) .unzip(); let reduced_lhs = factor.reduce(&lhs, builder); let reduced_rhs = factor.reduce(&rhs, builder); diff --git a/evm/src/prover.rs b/evm/src/prover.rs index 7b960c95..d7368c78 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -20,20 +20,14 @@ use plonky2_maybe_rayon::*; use plonky2_util::{log2_ceil, log2_strict}; use crate::all_stark::{AllStark, Table, NUM_TABLES}; -use crate::arithmetic::arithmetic_stark::ArithmeticStark; -use crate::byte_packing::byte_packing_stark::BytePackingStark; use crate::config::StarkConfig; use crate::constraint_consumer::ConstraintConsumer; -use crate::cpu::cpu_stark::CpuStark; use crate::cpu::kernel::aggregator::KERNEL; use crate::cross_table_lookup::{cross_table_lookup_data, CtlCheckVars, CtlData}; +use crate::evaluation_frame::StarkEvaluationFrame; use crate::generation::outputs::GenerationOutputs; use crate::generation::{generate_traces, GenerationInputs}; use crate::get_challenges::observe_public_values; -use crate::keccak::keccak_stark::KeccakStark; -use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeStark; -use crate::logic::LogicStark; -use crate::memory::memory_stark::MemoryStark; use crate::permutation::{ compute_permutation_z_polys, get_grand_product_challenge_set, get_n_grand_product_challenge_sets, GrandProductChallengeSet, PermutationCheckVars, @@ -41,7 +35,6 @@ use crate::permutation::{ use crate::proof::{AllProof, PublicValues, StarkOpeningSet, StarkProof, StarkProofWithMetadata}; use crate::stark::Stark; use crate::vanishing_poly::eval_vanishing_poly; -use crate::vars::StarkEvaluationVars; /// Generate traces, then create all STARK proofs. pub fn prove( @@ -53,13 +46,6 @@ pub fn prove( where F: RichField + Extendable, C: GenericConfig, - [(); ArithmeticStark::::COLUMNS]:, - [(); BytePackingStark::::COLUMNS]:, - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakSpongeStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, { let (proof, _outputs) = prove_with_outputs(all_stark, config, inputs, timing)?; Ok(proof) @@ -76,13 +62,6 @@ pub fn prove_with_outputs( where F: RichField + Extendable, C: GenericConfig, - [(); ArithmeticStark::::COLUMNS]:, - [(); BytePackingStark::::COLUMNS]:, - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakSpongeStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, { timed!(timing, "build kernel", Lazy::force(&KERNEL)); let (traces, public_values, outputs) = timed!( @@ -105,13 +84,6 @@ pub(crate) fn prove_with_traces( where F: RichField + Extendable, C: GenericConfig, - [(); ArithmeticStark::::COLUMNS]:, - [(); BytePackingStark::::COLUMNS]:, - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakSpongeStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, { let rate_bits = config.fri_config.rate_bits; let cap_height = config.fri_config.cap_height; @@ -197,13 +169,6 @@ fn prove_with_commitments( where F: RichField + Extendable, C: GenericConfig, - [(); ArithmeticStark::::COLUMNS]:, - [(); BytePackingStark::::COLUMNS]:, - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakSpongeStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, { let arithmetic_proof = timed!( timing, @@ -322,7 +287,6 @@ where F: RichField + Extendable, C: GenericConfig, S: Stark, - [(); S::COLUMNS]:, { let degree = trace_poly_values[0].len(); let degree_bits = log2_strict(degree); @@ -507,7 +471,6 @@ where P: PackedField, C: GenericConfig, S: Stark, - [(); S::COLUMNS]:, { let degree = 1 << degree_bits; let rate_bits = config.fri_config.rate_bits; @@ -530,12 +493,8 @@ where let z_h_on_coset = ZeroPolyOnCoset::::new(degree_bits, quotient_degree_bits); // Retrieve the LDE values at index `i`. - let get_trace_values_packed = |i_start| -> [P; S::COLUMNS] { - trace_commitment - .get_lde_values_packed(i_start, step) - .try_into() - .unwrap() - }; + let get_trace_values_packed = + |i_start| -> Vec

{ trace_commitment.get_lde_values_packed(i_start, step) }; // Last element of the subgroup. let last = F::primitive_root_of_unity(degree_bits).inverse(); @@ -566,10 +525,10 @@ where lagrange_basis_first, lagrange_basis_last, ); - let vars = StarkEvaluationVars { - local_values: &get_trace_values_packed(i_start), - next_values: &get_trace_values_packed(i_next_start), - }; + let vars = S::EvaluationFrame::from_values( + &get_trace_values_packed(i_start), + &get_trace_values_packed(i_next_start), + ); let permutation_check_vars = permutation_challenges.map(|permutation_challenge_sets| PermutationCheckVars { local_zs: permutation_ctl_zs_commitment.get_lde_values_packed(i_start, step) @@ -597,7 +556,7 @@ where eval_vanishing_poly::( stark, config, - vars, + &vars, permutation_check_vars, &ctl_vars, &mut consumer, @@ -642,7 +601,6 @@ fn check_constraints<'a, F, C, S, const D: usize>( F: RichField + Extendable, C: GenericConfig, S: Stark, - [(); S::COLUMNS]:, { let degree = 1 << degree_bits; let rate_bits = 0; // Set this to higher value to check constraint degree. @@ -688,10 +646,10 @@ fn check_constraints<'a, F, C, S, const D: usize>( lagrange_basis_first, lagrange_basis_last, ); - let vars = StarkEvaluationVars { - local_values: trace_subgroup_evals[i].as_slice().try_into().unwrap(), - next_values: trace_subgroup_evals[i_next].as_slice().try_into().unwrap(), - }; + let vars = S::EvaluationFrame::from_values( + &trace_subgroup_evals[i], + &trace_subgroup_evals[i_next], + ); let permutation_check_vars = permutation_challenges.map(|permutation_challenge_sets| PermutationCheckVars { local_zs: permutation_ctl_zs_subgroup_evals[i][..num_permutation_zs].to_vec(), @@ -715,7 +673,7 @@ fn check_constraints<'a, F, C, S, const D: usize>( eval_vanishing_poly::( stark, config, - vars, + &vars, permutation_check_vars, &ctl_vars, &mut consumer, diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 76a92338..f4e76c39 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -30,6 +30,7 @@ use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cross_table_lookup::{verify_cross_table_lookups, CrossTableLookup, CtlCheckVarsTarget}; +use crate::evaluation_frame::StarkEvaluationFrame; use crate::memory::segments::Segment; use crate::memory::VALUE_LIMBS; use crate::permutation::{ @@ -45,7 +46,6 @@ use crate::proof::{ use crate::stark::Stark; use crate::util::{h256_limbs, u256_limbs, u256_to_u32, u256_to_u64}; use crate::vanishing_poly::eval_vanishing_poly_circuit; -use crate::vars::StarkEvaluationTargets; use crate::witness::errors::ProgramError; /// Table-wise recursive proofs of an `AllProof`. @@ -297,7 +297,6 @@ pub(crate) fn recursive_stark_circuit< min_degree_bits: usize, ) -> StarkWrapperCircuit where - [(); S::COLUMNS]:, C::Hasher: AlgebraicHasher, { let mut builder = CircuitBuilder::::new(circuit_config.clone()); @@ -405,7 +404,6 @@ fn verify_stark_proof_with_challenges_circuit< inner_config: &StarkConfig, ) where C::Hasher: AlgebraicHasher, - [(); S::COLUMNS]:, { let zero = builder.zero(); let one = builder.one_extension(); @@ -418,10 +416,7 @@ fn verify_stark_proof_with_challenges_circuit< ctl_zs_first, quotient_polys, } = &proof.openings; - let vars = StarkEvaluationTargets { - local_values: &local_values.to_vec().try_into().unwrap(), - next_values: &next_values.to_vec().try_into().unwrap(), - }; + let vars = S::EvaluationFrameTarget::from_values(local_values, next_values); let degree_bits = proof.recover_degree_bits(inner_config); let zeta_pow_deg = builder.exp_power_of_2_extension(challenges.stark_zeta, degree_bits); @@ -456,7 +451,7 @@ fn verify_stark_proof_with_challenges_circuit< builder, stark, inner_config, - vars, + &vars, permutation_data, ctl_vars, &mut consumer, diff --git a/evm/src/stark.rs b/evm/src/stark.rs index 73b51ada..b3ea818f 100644 --- a/evm/src/stark.rs +++ b/evm/src/stark.rs @@ -12,8 +12,8 @@ use plonky2_util::ceil_div_usize; use crate::config::StarkConfig; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use crate::evaluation_frame::StarkEvaluationFrame; use crate::permutation::PermutationPair; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; const TRACE_ORACLE_INDEX: usize = 0; const PERMUTATION_CTL_ORACLE_INDEX: usize = 1; @@ -22,7 +22,16 @@ const QUOTIENT_ORACLE_INDEX: usize = 2; /// Represents a STARK system. pub trait Stark, const D: usize>: Sync { /// The total number of columns in the trace. - const COLUMNS: usize; + const COLUMNS: usize = Self::EvaluationFrameTarget::COLUMNS; + + /// This is used to evaluate constraints natively. + type EvaluationFrame: StarkEvaluationFrame

+ where + FE: FieldExtension, + P: PackedField; + + /// The `Target` version of `Self::EvaluationFrame`, used to evaluate constraints recursively. + type EvaluationFrameTarget: StarkEvaluationFrame>; /// Evaluate constraints at a vector of points. /// @@ -32,7 +41,7 @@ pub trait Stark, const D: usize>: Sync { /// constraints over `F`. fn eval_packed_generic( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) where FE: FieldExtension, @@ -41,7 +50,7 @@ pub trait Stark, const D: usize>: Sync { /// Evaluate constraints at a vector of points from the base field `F`. fn eval_packed_base>( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer

, ) { self.eval_packed_generic(vars, yield_constr) @@ -50,7 +59,7 @@ pub trait Stark, const D: usize>: Sync { /// Evaluate constraints at a single point from the degree `D` extension field. fn eval_ext( &self, - vars: StarkEvaluationVars, + vars: &Self::EvaluationFrame, yield_constr: &mut ConstraintConsumer, ) { self.eval_packed_generic(vars, yield_constr) @@ -63,7 +72,7 @@ pub trait Stark, const D: usize>: Sync { fn eval_ext_circuit( &self, builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, + vars: &Self::EvaluationFrameTarget, yield_constr: &mut RecursiveConstraintConsumer, ); diff --git a/evm/src/stark_testing.rs b/evm/src/stark_testing.rs index e005d2ea..5fe44127 100644 --- a/evm/src/stark_testing.rs +++ b/evm/src/stark_testing.rs @@ -3,17 +3,16 @@ use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; use plonky2::field::types::{Field, Sample}; use plonky2::hash::hash_types::RichField; -use plonky2::hash::hashing::PlonkyPermutation; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::plonk::config::GenericConfig; use plonky2::util::transpose; use plonky2_util::{log2_ceil, log2_strict}; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use crate::evaluation_frame::StarkEvaluationFrame; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; const WITNESS_SIZE: usize = 1 << 5; @@ -21,10 +20,7 @@ const WITNESS_SIZE: usize = 1 << 5; /// low-degree witness polynomials. pub fn test_stark_low_degree, S: Stark, const D: usize>( stark: S, -) -> Result<()> -where - [(); S::COLUMNS]:, -{ +) -> Result<()> { let rate_bits = log2_ceil(stark.constraint_degree() + 1); let trace_ldes = random_low_degree_matrix::(S::COLUMNS, rate_bits); @@ -39,13 +35,10 @@ where let alpha = F::rand(); let constraint_evals = (0..size) .map(|i| { - let vars = StarkEvaluationVars { - local_values: &trace_ldes[i].clone().try_into().unwrap(), - next_values: &trace_ldes[(i + (1 << rate_bits)) % size] - .clone() - .try_into() - .unwrap(), - }; + let vars = S::EvaluationFrame::from_values( + &trace_ldes[i], + &trace_ldes[(i + (1 << rate_bits)) % size], + ); let mut consumer = ConstraintConsumer::::new( vec![alpha], @@ -53,7 +46,7 @@ where lagrange_first.values[i], lagrange_last.values[i], ); - stark.eval_packed_base(vars, &mut consumer); + stark.eval_packed_base(&vars, &mut consumer); consumer.accumulators()[0] }) .collect::>(); @@ -84,17 +77,13 @@ pub fn test_stark_circuit_constraints< const D: usize, >( stark: S, -) -> Result<()> -where - [(); S::COLUMNS]:, - [(); >::Permutation::WIDTH]:, - [(); >::Permutation::WIDTH]:, -{ +) -> Result<()> { // Compute native constraint evaluation on random values. - let vars = StarkEvaluationVars { - local_values: &F::Extension::rand_array::<{ S::COLUMNS }>(), - next_values: &F::Extension::rand_array::<{ S::COLUMNS }>(), - }; + let vars = S::EvaluationFrame::from_values( + &F::Extension::rand_vec(S::COLUMNS), + &F::Extension::rand_vec(S::COLUMNS), + ); + let alphas = F::rand_vec(1); let z_last = F::Extension::rand(); let lagrange_first = F::Extension::rand(); @@ -109,7 +98,7 @@ where lagrange_first, lagrange_last, ); - stark.eval_ext(vars, &mut consumer); + stark.eval_ext(&vars, &mut consumer); let native_eval = consumer.accumulators()[0]; // Compute circuit constraint evaluation on same random values. @@ -118,9 +107,9 @@ where let mut pw = PartialWitness::::new(); let locals_t = builder.add_virtual_extension_targets(S::COLUMNS); - pw.set_extension_targets(&locals_t, vars.local_values); + pw.set_extension_targets(&locals_t, vars.get_local_values()); let nexts_t = builder.add_virtual_extension_targets(S::COLUMNS); - pw.set_extension_targets(&nexts_t, vars.next_values); + pw.set_extension_targets(&nexts_t, vars.get_next_values()); let alphas_t = builder.add_virtual_targets(1); pw.set_target(alphas_t[0], alphas[0]); let z_last_t = builder.add_virtual_extension_target(); @@ -130,10 +119,7 @@ where let lagrange_last_t = builder.add_virtual_extension_target(); pw.set_extension_target(lagrange_last_t, lagrange_last); - let vars = StarkEvaluationTargets:: { - local_values: &locals_t.try_into().unwrap(), - next_values: &nexts_t.try_into().unwrap(), - }; + let vars = S::EvaluationFrameTarget::from_values(&locals_t, &nexts_t); let mut consumer = RecursiveConstraintConsumer::::new( builder.zero_extension(), alphas_t, @@ -141,7 +127,7 @@ where lagrange_first_t, lagrange_last_t, ); - stark.eval_ext_circuit(&mut builder, vars, &mut consumer); + stark.eval_ext_circuit(&mut builder, &vars, &mut consumer); let circuit_eval = consumer.accumulators()[0]; let native_eval_t = builder.constant_extension(native_eval); builder.connect_extension(circuit_eval, native_eval_t); diff --git a/evm/src/vanishing_poly.rs b/evm/src/vanishing_poly.rs index 3a2da78c..6c88b16e 100644 --- a/evm/src/vanishing_poly.rs +++ b/evm/src/vanishing_poly.rs @@ -14,12 +14,11 @@ use crate::permutation::{ PermutationCheckVars, }; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; pub(crate) fn eval_vanishing_poly( stark: &S, config: &StarkConfig, - vars: StarkEvaluationVars, + vars: &S::EvaluationFrame, permutation_vars: Option>, ctl_vars: &[CtlCheckVars], consumer: &mut ConstraintConsumer

, @@ -46,14 +45,13 @@ pub(crate) fn eval_vanishing_poly_circuit( builder: &mut CircuitBuilder, stark: &S, config: &StarkConfig, - vars: StarkEvaluationTargets, + vars: &S::EvaluationFrameTarget, permutation_data: Option>, ctl_vars: &[CtlCheckVarsTarget], consumer: &mut RecursiveConstraintConsumer, ) where F: RichField + Extendable, S: Stark, - [(); S::COLUMNS]:, { stark.eval_ext_circuit(builder, vars, consumer); if let Some(permutation_data) = permutation_data { diff --git a/evm/src/vars.rs b/evm/src/vars.rs deleted file mode 100644 index 6c82675c..00000000 --- a/evm/src/vars.rs +++ /dev/null @@ -1,19 +0,0 @@ -use plonky2::field::packed::PackedField; -use plonky2::field::types::Field; -use plonky2::iop::ext_target::ExtensionTarget; - -#[derive(Debug, Copy, Clone)] -pub struct StarkEvaluationVars<'a, F, P, const COLUMNS: usize> -where - F: Field, - P: PackedField, -{ - pub local_values: &'a [P; COLUMNS], - pub next_values: &'a [P; COLUMNS], -} - -#[derive(Debug, Copy, Clone)] -pub struct StarkEvaluationTargets<'a, const D: usize, const COLUMNS: usize> { - pub local_values: &'a [ExtensionTarget; COLUMNS], - pub next_values: &'a [ExtensionTarget; COLUMNS], -} diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index 11f8155d..c7b58060 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -11,17 +11,11 @@ use plonky2::plonk::config::GenericConfig; use plonky2::plonk::plonk_common::reduce_with_powers; use crate::all_stark::{AllStark, Table, NUM_TABLES}; -use crate::arithmetic::arithmetic_stark::ArithmeticStark; -use crate::byte_packing::byte_packing_stark::BytePackingStark; use crate::config::StarkConfig; use crate::constraint_consumer::ConstraintConsumer; -use crate::cpu::cpu_stark::CpuStark; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cross_table_lookup::{verify_cross_table_lookups, CtlCheckVars}; -use crate::keccak::keccak_stark::KeccakStark; -use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeStark; -use crate::logic::LogicStark; -use crate::memory::memory_stark::MemoryStark; +use crate::evaluation_frame::StarkEvaluationFrame; use crate::memory::segments::Segment; use crate::memory::VALUE_LIMBS; use crate::permutation::{GrandProductChallenge, PermutationCheckVars}; @@ -31,7 +25,6 @@ use crate::proof::{ use crate::stark::Stark; use crate::util::h2u; use crate::vanishing_poly::eval_vanishing_poly; -use crate::vars::StarkEvaluationVars; pub fn verify_proof, C: GenericConfig, const D: usize>( all_stark: &AllStark, @@ -39,13 +32,6 @@ pub fn verify_proof, C: GenericConfig, co config: &StarkConfig, ) -> Result<()> where - [(); ArithmeticStark::::COLUMNS]:, - [(); BytePackingStark::::COLUMNS]:, - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakSpongeStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, { let AllProofChallenges { stark_challenges, @@ -301,10 +287,7 @@ pub(crate) fn verify_stark_proof_with_challenges< challenges: &StarkProofChallenges, ctl_vars: &[CtlCheckVars], config: &StarkConfig, -) -> Result<()> -where - [(); S::COLUMNS]:, -{ +) -> Result<()> { log::debug!("Checking proof: {}", type_name::()); validate_proof_shape(stark, proof, config, ctl_vars.len())?; let StarkOpeningSet { @@ -315,10 +298,7 @@ where ctl_zs_first, quotient_polys, } = &proof.openings; - let vars = StarkEvaluationVars { - local_values: &local_values.to_vec().try_into().unwrap(), - next_values: &next_values.to_vec().try_into().unwrap(), - }; + let vars = S::EvaluationFrame::from_values(local_values, next_values); let degree_bits = proof.recover_degree_bits(config); let (l_0, l_last) = eval_l_0_and_l_last(degree_bits, challenges.stark_zeta); @@ -343,7 +323,7 @@ where eval_vanishing_poly::( stark, config, - vars, + &vars, permutation_data, ctl_vars, &mut consumer, @@ -401,7 +381,6 @@ where F: RichField + Extendable, C: GenericConfig, S: Stark, - [(); S::COLUMNS]:, { let StarkProof { trace_cap,