Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

continuations: Remove redundant simulation #203

Merged
merged 6 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 6 additions & 85 deletions evm_arithmetization/src/cpu/kernel/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,91 +122,15 @@ pub(crate) struct ExtraSegmentData {
pub(crate) jumpdest_table: Option<HashMap<usize, Vec<usize>>>,
}

/// Given a segment `index`, returns the initial and final registers, as well
/// as the initial memory of segment `index`, and returns `None` if the
/// execution stops at segment `index`. These can then be passed to the
/// prover for initialization.
pub(crate) fn generate_segment<F: Field>(
max_cpu_len_log: usize,
index: usize,
inputs: &GenerationInputs,
) -> anyhow::Result<
Option<(
RegistersState,
RegistersState,
MemoryState,
ExtraSegmentData,
)>,
> {
let init_label = KERNEL.global_labels["init"];
let initial_registers = RegistersState::new();
let mut interpreter = Interpreter::<F>::new_with_generation_inputs(
init_label,
vec![],
inputs,
Some(max_cpu_len_log),
);

let (mut registers_before, mut registers_after, mut before_mem_values, mut after_mem_values) = (
initial_registers,
initial_registers,
MemoryState::default(),
MemoryState::default(),
);

let mut extra_data = ExtraSegmentData::default();

for i in 0..=index {
if i == index {
extra_data = ExtraSegmentData {
trimmed_inputs: interpreter.generation_state.inputs.clone(),
bignum_modmul_result_limbs: interpreter
.generation_state
.bignum_modmul_result_limbs
.clone(),
rlp_prover_inputs: interpreter.generation_state.rlp_prover_inputs.clone(),
withdrawal_prover_inputs: interpreter
.generation_state
.withdrawal_prover_inputs
.clone(),
trie_root_ptrs: interpreter.generation_state.trie_root_ptrs.clone(),
jumpdest_table: interpreter.generation_state.jumpdest_table.clone(),
};
}

// Write initial registers.
if registers_after.program_counter == KERNEL.global_labels["halt"] {
return Ok(None);
}

(registers_before, before_mem_values) = (registers_after, after_mem_values);
interpreter.generation_state.registers = registers_before;
interpreter.generation_state.registers.program_counter = init_label;
interpreter.generation_state.registers.is_kernel = true;
interpreter.clock = 0;

let (updated_registers_after, opt_after_mem_values) =
set_registers_and_run(registers_after, &mut interpreter)?;

registers_after = updated_registers_after;
after_mem_values = opt_after_mem_values.expect(
"We are in the interpreter: the run should return a memory
state",
);
}

Ok(Some((
registers_before,
registers_after,
before_mem_values,
extra_data,
)))
}

pub(crate) fn set_registers_and_run<F: Field>(
registers: RegistersState,
interpreter: &mut Interpreter<F>,
) -> anyhow::Result<(RegistersState, Option<MemoryState>)> {
interpreter.generation_state.registers = registers;
interpreter.generation_state.registers.program_counter = KERNEL.global_labels["init"];
interpreter.generation_state.registers.is_kernel = true;
interpreter.clock = 0;

// Write initial registers.
[
registers.program_counter.into(),
Expand All @@ -225,10 +149,7 @@ pub(crate) fn set_registers_and_run<F: Field>(
(Segment::RegistersStates.unscale()).into(),
i.into(),
)
.expect(
"All input values are known to be valid for
MemoryAddress",
),
.expect("All input values are known to be valid for MemoryAddress"),
*reg_content,
);
interpreter.generation_state.memory.set(addr, val);
Expand Down
130 changes: 71 additions & 59 deletions evm_arithmetization/src/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ use starky::stark::Stark;

use crate::all_stark::{AllStark, Table, NUM_TABLES};
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::{
generate_segment, set_registers_and_run, ExtraSegmentData, Interpreter,
};
use crate::cpu::kernel::interpreter::{set_registers_and_run, ExtraSegmentData, Interpreter};
use crate::generation::state::GenerationState;
use crate::generation::{generate_traces, GenerationInputs};
use crate::get_challenges::observe_public_values;
Expand Down Expand Up @@ -482,6 +480,40 @@ pub fn check_abort_signal(abort_signal: Option<Arc<AtomicBool>>) -> Result<()> {
Ok(())
}

/// Builds a new `GenerationSegmentData`.
/// This new segment's `is_dummy` field must be updated manually
/// in case it corresponds to a dummy segment.
fn build_segment_data<F: RichField>(
segment_index: usize,
registers_before: Option<RegistersState>,
registers_after: Option<RegistersState>,
memory: Option<MemoryState>,
interpreter: &Interpreter<F>,
) -> GenerationSegmentData {
GenerationSegmentData {
is_dummy: false,
segment_index,
registers_before: registers_before.unwrap_or(RegistersState::new()),
registers_after: registers_after.unwrap_or(RegistersState::new()),
memory: memory.unwrap_or_default(),
max_cpu_len_log: interpreter.get_max_cpu_len_log(),
extra_data: ExtraSegmentData {
trimmed_inputs: interpreter.generation_state.inputs.clone(),
bignum_modmul_result_limbs: interpreter
.generation_state
.bignum_modmul_result_limbs
.clone(),
rlp_prover_inputs: interpreter.generation_state.rlp_prover_inputs.clone(),
withdrawal_prover_inputs: interpreter
.generation_state
.withdrawal_prover_inputs
.clone(),
trie_root_ptrs: interpreter.generation_state.trie_root_ptrs.clone(),
jumpdest_table: interpreter.generation_state.jumpdest_table.clone(),
},
}
}

/// Returns a vector containing the data required to generate all the segments
/// of a transaction.
pub fn generate_all_data_segments<F: RichField>(
Expand All @@ -499,68 +531,23 @@ pub fn generate_all_data_segments<F: RichField>(

let mut segment_index = 0;

let mut segment_data = GenerationSegmentData {
is_dummy: false,
segment_index,
registers_before: RegistersState::new(),
registers_after: RegistersState::new(),
memory: MemoryState::default(),
max_cpu_len_log,
extra_data: ExtraSegmentData {
trimmed_inputs: interpreter.generation_state.inputs.clone(),
bignum_modmul_result_limbs: interpreter
.generation_state
.bignum_modmul_result_limbs
.clone(),
rlp_prover_inputs: interpreter.generation_state.rlp_prover_inputs.clone(),
withdrawal_prover_inputs: interpreter
.generation_state
.withdrawal_prover_inputs
.clone(),
trie_root_ptrs: interpreter.generation_state.trie_root_ptrs.clone(),
jumpdest_table: interpreter.generation_state.jumpdest_table.clone(),
},
};
let mut segment_data = build_segment_data(segment_index, None, None, None, &interpreter);

while segment_data.registers_after.program_counter != KERNEL.global_labels["halt"] {
interpreter.generation_state.registers = segment_data.registers_after;
interpreter.generation_state.registers.program_counter = KERNEL.global_labels["init"];
interpreter.generation_state.registers.is_kernel = true;
interpreter.clock = 0;

let (updated_registers, mem_after) =
set_registers_and_run(segment_data.registers_after, &mut interpreter)?;

// Set `registers_after` correctly and push the data.
segment_data.registers_after = updated_registers;
all_seg_data.push(segment_data);

segment_index += 1;

segment_data = GenerationSegmentData {
is_dummy: false,
segment_data = build_segment_data(
segment_index,
registers_before: updated_registers,
// `registers_after` will be set correctly at the next iteration.`
registers_after: updated_registers,
max_cpu_len_log,
memory: mem_after
.expect("The interpreter was running, so it should have returned a MemoryState"),
extra_data: ExtraSegmentData {
trimmed_inputs: interpreter.generation_state.inputs.clone(),
bignum_modmul_result_limbs: interpreter
.generation_state
.bignum_modmul_result_limbs
.clone(),
rlp_prover_inputs: interpreter.generation_state.rlp_prover_inputs.clone(),
withdrawal_prover_inputs: interpreter
.generation_state
.withdrawal_prover_inputs
.clone(),
trie_root_ptrs: interpreter.generation_state.trie_root_ptrs.clone(),
jumpdest_table: interpreter.generation_state.jumpdest_table.clone(),
},
};
Some(updated_registers),
Some(updated_registers),
mem_after,
&interpreter,
);
}

// We need at least two segments to prove a segment aggregation.
Expand Down Expand Up @@ -601,6 +588,8 @@ pub fn generate_all_data_segments<F: RichField>(

/// A utility module designed to test witness generation externally.
pub mod testing {
use log::info;
Nashtare marked this conversation as resolved.
Show resolved Hide resolved

use super::*;
use crate::{
cpu::kernel::interpreter::Interpreter,
Expand Down Expand Up @@ -659,12 +648,35 @@ pub mod testing {
max_cpu_len_log: usize,
) -> anyhow::Result<()>
where
F: Field,
F: RichField,
{
let mut index = 0;
while generate_segment::<F>(max_cpu_len_log, index, &inputs)?.is_some() {
index += 1;
let max_cpu_len_log = Some(max_cpu_len_log);
let mut interpreter = Interpreter::<F>::new_with_generation_inputs(
KERNEL.global_labels["init"],
vec![],
&inputs,
max_cpu_len_log,
);

let mut segment_index = 0;

let mut segment_data = build_segment_data(segment_index, None, None, None, &interpreter);

while segment_data.registers_after.program_counter != KERNEL.global_labels["halt"] {
segment_index += 1;

let (updated_registers, mem_after) =
set_registers_and_run(segment_data.registers_after, &mut interpreter)?;

segment_data = build_segment_data(
segment_index,
Some(updated_registers),
Some(updated_registers),
mem_after,
&interpreter,
);
}

Ok(())
}
}
Loading