diff --git a/evm/src/cpu/kernel/assembler.rs b/evm/src/cpu/kernel/assembler.rs index 4dbc46ca..334220fd 100644 --- a/evm/src/cpu/kernel/assembler.rs +++ b/evm/src/cpu/kernel/assembler.rs @@ -7,6 +7,7 @@ use log::debug; use super::ast::PushTarget; use crate::cpu::kernel::ast::{Literal, StackReplacement}; use crate::cpu::kernel::keccak_util::hash_kernel; +use crate::cpu::kernel::prover_input::ProverInputFn; use crate::cpu::kernel::stack_manipulation::expand_stack_manipulation; use crate::cpu::kernel::{ ast::{File, Item}, @@ -27,15 +28,22 @@ pub struct Kernel { pub(crate) code_hash: [u32; 8], pub(crate) global_labels: HashMap, + + pub(crate) prover_inputs: HashMap, } impl Kernel { - fn new(code: Vec, global_labels: HashMap) -> Self { + fn new( + code: Vec, + global_labels: HashMap, + prover_inputs: HashMap, + ) -> Self { let code_hash = hash_kernel(&code); Self { code, code_hash, global_labels, + prover_inputs, } } } @@ -57,6 +65,7 @@ impl Macro { pub(crate) fn assemble(files: Vec, constants: HashMap) -> Kernel { let macros = find_macros(&files); let mut global_labels = HashMap::new(); + let mut prover_inputs = HashMap::new(); let mut offset = 0; let mut expanded_files = Vec::with_capacity(files.len()); let mut local_labels = Vec::with_capacity(files.len()); @@ -65,7 +74,12 @@ pub(crate) fn assemble(files: Vec, constants: HashMap) -> Ke let expanded_file = expand_repeats(expanded_file); let expanded_file = inline_constants(expanded_file, &constants); let expanded_file = expand_stack_manipulation(expanded_file); - local_labels.push(find_labels(&expanded_file, &mut offset, &mut global_labels)); + local_labels.push(find_labels( + &expanded_file, + &mut offset, + &mut global_labels, + &mut prover_inputs, + )); expanded_files.push(expanded_file); } let mut code = vec![]; @@ -76,7 +90,7 @@ pub(crate) fn assemble(files: Vec, constants: HashMap) -> Ke debug!("Assembled file size: {} bytes", file_len); } assert_eq!(code.len(), offset, "Code length doesn't match offset."); - Kernel::new(code, global_labels) + Kernel::new(code, global_labels, prover_inputs) } fn find_macros(files: &[File]) -> HashMap { @@ -217,6 +231,7 @@ fn find_labels( body: &[Item], offset: &mut usize, global_labels: &mut HashMap, + prover_inputs: &mut HashMap, ) -> HashMap { // Discover the offset of each label in this file. let mut local_labels = HashMap::::new(); @@ -237,6 +252,10 @@ fn find_labels( assert!(old.is_none(), "Duplicate local label: {}", label); } Item::Push(target) => *offset += 1 + push_target_size(target) as usize, + Item::ProverInput(prover_input_fn) => { + prover_inputs.insert(*offset, prover_input_fn.clone()); + *offset += 1; + } Item::StandardOp(_) => *offset += 1, Item::Bytes(bytes) => *offset += bytes.len(), } @@ -283,6 +302,9 @@ fn assemble_file( code.push(get_push_opcode(target_bytes.len() as u8)); code.extend(target_bytes); } + Item::ProverInput(_) => { + code.push(get_opcode("PROVER_INPUT")); + } Item::StandardOp(opcode) => { code.push(get_opcode(&opcode)); } @@ -357,7 +379,7 @@ mod tests { expected_global_labels.insert("function_1".to_string(), 0); expected_global_labels.insert("function_2".to_string(), 3); - let expected_kernel = Kernel::new(expected_code, expected_global_labels); + let expected_kernel = Kernel::new(expected_code, expected_global_labels, HashMap::new()); let program = vec![file_1, file_2]; assert_eq!(assemble(program, HashMap::new()), expected_kernel); diff --git a/evm/src/cpu/kernel/ast.rs b/evm/src/cpu/kernel/ast.rs index 92728104..9580d9c6 100644 --- a/evm/src/cpu/kernel/ast.rs +++ b/evm/src/cpu/kernel/ast.rs @@ -1,6 +1,8 @@ use ethereum_types::U256; use plonky2_util::ceil_div_usize; +use crate::cpu::kernel::prover_input::ProverInputFn; + #[derive(Debug)] pub(crate) struct File { pub(crate) body: Vec, @@ -25,6 +27,8 @@ pub(crate) enum Item { LocalLabelDeclaration(String), /// A `PUSH` operation. Push(PushTarget), + /// A `ProverInput` operation. + ProverInput(ProverInputFn), /// Any opcode besides a PUSH opcode. StandardOp(String), /// Literal hex data; should contain an even number of hex chars. diff --git a/evm/src/cpu/kernel/evm_asm.pest b/evm/src/cpu/kernel/evm_asm.pest index 943e8dae..b0033391 100644 --- a/evm/src/cpu/kernel/evm_asm.pest +++ b/evm/src/cpu/kernel/evm_asm.pest @@ -15,7 +15,7 @@ literal = { literal_hex | literal_decimal } variable = ${ "$" ~ identifier } constant = ${ "@" ~ identifier } -item = { macro_def | macro_call | repeat | stack | global_label | local_label | bytes_item | push_instruction | nullary_instruction } +item = { macro_def | macro_call | repeat | stack | global_label | local_label | bytes_item | push_instruction | prover_input_instruction | nullary_instruction } macro_def = { ^"%macro" ~ identifier ~ paramlist? ~ item* ~ ^"%endmacro" } macro_call = ${ "%" ~ !(^"macro" | ^"endmacro" | ^"rep" | ^"endrep" | ^"stack") ~ identifier ~ macro_arglist? } repeat = { ^"%rep" ~ literal ~ item* ~ ^"%endrep" } @@ -29,7 +29,7 @@ local_label = { identifier ~ ":" } bytes_item = { ^"BYTES " ~ literal ~ ("," ~ literal)* } push_instruction = { ^"PUSH " ~ push_target } push_target = { literal | identifier | variable | constant } -prover_input_instruction = { ^"PROVER_INPUT " ~ "(" ~ prover_input_fn ~ ")" } // TODO: Can also support extra arguments. +prover_input_instruction = { ^"PROVER_INPUT" ~ "(" ~ prover_input_fn ~ ")" } // TODO: Could also support extra arguments. prover_input_fn = { identifier ~ ("::" ~ identifier)*} nullary_instruction = { identifier } diff --git a/evm/src/cpu/kernel/mod.rs b/evm/src/cpu/kernel/mod.rs index 1f13a042..a79e17e9 100644 --- a/evm/src/cpu/kernel/mod.rs +++ b/evm/src/cpu/kernel/mod.rs @@ -4,6 +4,7 @@ mod ast; pub(crate) mod keccak_util; mod opcodes; mod parser; +mod prover_input; mod stack_manipulation; #[cfg(test)] diff --git a/evm/src/cpu/kernel/parser.rs b/evm/src/cpu/kernel/parser.rs index aa84ee05..f7acc96c 100644 --- a/evm/src/cpu/kernel/parser.rs +++ b/evm/src/cpu/kernel/parser.rs @@ -33,6 +33,15 @@ fn parse_item(item: Pair) -> Item { } Rule::bytes_item => Item::Bytes(item.into_inner().map(parse_literal).collect()), Rule::push_instruction => Item::Push(parse_push_target(item.into_inner().next().unwrap())), + Rule::prover_input_instruction => Item::ProverInput( + item.into_inner() + .next() + .unwrap() + .into_inner() + .map(|x| x.as_str().into()) + .collect::>() + .into(), + ), Rule::nullary_instruction => Item::StandardOp(item.as_str().into()), _ => panic!("Unexpected {:?}", item.as_rule()), } diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs new file mode 100644 index 00000000..1251f7d2 --- /dev/null +++ b/evm/src/cpu/kernel/prover_input.rs @@ -0,0 +1,8 @@ +#[derive(PartialEq, Eq, Debug, Clone)] +pub(crate) struct ProverInputFn(Vec); + +impl From> for ProverInputFn { + fn from(v: Vec) -> Self { + Self(v) + } +}