diff --git a/evm/Cargo.toml b/evm/Cargo.toml index 1e22ef33..c10ab104 100644 --- a/evm/Cargo.toml +++ b/evm/Cargo.toml @@ -11,6 +11,7 @@ anyhow = "1.0.40" env_logger = "0.9.0" ethereum-types = "0.13.1" hex = { version = "0.4.3", optional = true } +hex-literal = "0.3.4" itertools = "0.10.3" log = "0.4.14" once_cell = "1.13.0" @@ -24,7 +25,6 @@ keccak-rust = { git = "https://github.com/npwardberkeley/keccak-rust" } keccak-hash = "0.9.0" [dev-dependencies] -hex-literal = "0.3.4" hex = "0.4.3" [features] diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 8784e337..ec42f5c4 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use ethereum_types::U256; +use hex_literal::hex; use itertools::Itertools; use once_cell::sync::Lazy; @@ -14,6 +15,12 @@ pub static KERNEL: Lazy = Lazy::new(combined_kernel); pub fn evm_constants() -> HashMap { let mut c = HashMap::new(); + c.insert( + "BN_BASE".into(), + U256::from_big_endian(&hex!( + "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47" + )), + ); for segment in Segment::all() { c.insert(segment.var_name().into(), (segment as u32).into()); } diff --git a/evm/src/cpu/kernel/asm/curve_add.asm b/evm/src/cpu/kernel/asm/curve_add.asm index f6275787..541b1605 100644 --- a/evm/src/cpu/kernel/asm/curve_add.asm +++ b/evm/src/cpu/kernel/asm/curve_add.asm @@ -94,14 +94,8 @@ global ec_add_valid_points: ec_add_first_zero: JUMPDEST // stack: x0, y0, x1, y1, retdest - // Just return (x1,y1) - %pop2 - // stack: x1, y1, retdest - SWAP1 - // stack: y1, x1, retdest - SWAP2 - // stack: retdest, x1, y1 + %stack (x0, y0, x1, y1, retdest) -> (retdest, x1, y1) JUMP // BN254 elliptic curve addition. @@ -271,21 +265,7 @@ global ec_double: // stack: y < N, x < N, x, y AND // stack: (y < N) & (x < N), x, y - SWAP2 - // stack: y, x, (y < N) & (x < N), x - SWAP1 - // stack: x, y, (y < N) & (x < N) - %bn_base - // stack: N, x, y, b - %bn_base - // stack: N, N, x, y, b - DUP3 - // stack: x, N, N, x, y, b - %bn_base - // stack: N, x, N, N, x, y, b - DUP2 - // stack: x, N, x, N, N, x, y, b - DUP1 + %stack (b, x, y) -> (x, x, @BN_BASE, x, @BN_BASE, @BN_BASE, x, y, b) // stack: x, x, N, x, N, N, x, y, b MULMOD // stack: x^2 % N, x, N, N, x, y, b diff --git a/evm/src/cpu/kernel/assembler.rs b/evm/src/cpu/kernel/assembler.rs index 7f793555..070ec291 100644 --- a/evm/src/cpu/kernel/assembler.rs +++ b/evm/src/cpu/kernel/assembler.rs @@ -5,7 +5,7 @@ use itertools::izip; use log::debug; use super::ast::PushTarget; -use crate::cpu::kernel::ast::Literal; +use crate::cpu::kernel::ast::{Literal, StackReplacement}; use crate::cpu::kernel::keccak_util::hash_kernel; use crate::cpu::kernel::stack_manipulation::expand_stack_manipulation; use crate::cpu::kernel::{ @@ -165,14 +165,31 @@ fn expand_repeats(body: Vec) -> Vec { } fn inline_constants(body: Vec, constants: &HashMap) -> Vec { + let resolve_const = |c| { + Literal::Decimal( + constants + .get(&c) + .unwrap_or_else(|| panic!("No such constant: {}", c)) + .to_string(), + ) + }; + body.into_iter() .map(|item| { if let Item::Push(PushTarget::Constant(c)) = item { - let value = constants - .get(&c) - .unwrap_or_else(|| panic!("No such constant: {}", c)); - let literal = Literal::Decimal(value.to_string()); - Item::Push(PushTarget::Literal(literal)) + Item::Push(PushTarget::Literal(resolve_const(c))) + } else if let Item::StackManipulation(from, to) = item { + let to = to + .into_iter() + .map(|replacement| { + if let StackReplacement::Constant(c) = replacement { + StackReplacement::Literal(resolve_const(c)) + } else { + replacement + } + }) + .collect(); + Item::StackManipulation(from, to) } else { item } @@ -446,6 +463,11 @@ mod tests { let kernel = parse_and_assemble(&["%stack (a, b, c) -> (b)"]); assert_eq!(kernel.code, vec![pop, swap1, pop]); + + let mut consts = HashMap::new(); + consts.insert("LIFE".into(), 42.into()); + parse_and_assemble_with_constants(&["%stack (a, b) -> (b, @LIFE)"], consts); + // We won't check the code since there are two equally efficient implementations. } fn parse_and_assemble(files: &[&str]) -> Kernel { diff --git a/evm/src/cpu/kernel/stack_manipulation.rs b/evm/src/cpu/kernel/stack_manipulation.rs index 140cfd6a..6f20ead6 100644 --- a/evm/src/cpu/kernel/stack_manipulation.rs +++ b/evm/src/cpu/kernel/stack_manipulation.rs @@ -39,7 +39,7 @@ fn expand(names: Vec, replacements: Vec) -> Vec StackReplacement::NamedItem(name) => StackItem::NamedItem(name), StackReplacement::Literal(n) => StackItem::Literal(n), StackReplacement::MacroVar(_) | StackReplacement::Constant(_) => { - panic!("Should have been expanded earlier") + panic!("Should have been expanded already: {:?}", item) } }) .collect_vec();