From 15bafce5ddc986bac343926c8d3db601a4d8a686 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 22 Mar 2023 19:14:17 +0100 Subject: [PATCH 1/3] Implement CREATE2 address generation (#936) * Implement create2 address gen * Clippy * Minor * Wrong order * Fix test * Fix comment --- evm/src/cpu/kernel/asm/core/create.asm | 6 +- .../cpu/kernel/asm/core/create_addresses.asm | 25 ++++-- .../cpu/kernel/tests/core/create_addresses.rs | 90 ++++++++++++++++--- 3 files changed, 102 insertions(+), 19 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/create.asm b/evm/src/cpu/kernel/asm/core/create.asm index d7e6eed2..5360e616 100644 --- a/evm/src/cpu/kernel/asm/core/create.asm +++ b/evm/src/cpu/kernel/asm/core/create.asm @@ -47,10 +47,10 @@ global sys_create2: SWAP4 %stack (salt) -> (salt, sys_create2_got_address) // stack: salt, sys_create2_got_address, value, code_offset, code_len, kexit_info - DUP4 // code_len - DUP4 // code_offset + DUP5 // code_len + DUP5 // code_offset PUSH @SEGMENT_MAIN_MEMORY - PUSH 0 // context + GET_CONTEXT KECCAK_GENERAL // stack: hash, salt, sys_create2_got_address, value, code_offset, code_len, kexit_info %address diff --git a/evm/src/cpu/kernel/asm/core/create_addresses.asm b/evm/src/cpu/kernel/asm/core/create_addresses.asm index 7dd4e889..d72d7e67 100644 --- a/evm/src/cpu/kernel/asm/core/create_addresses.asm +++ b/evm/src/cpu/kernel/asm/core/create_addresses.asm @@ -34,15 +34,28 @@ global get_create_address: // Computes the address for a contract based on the CREATE2 rule, i.e. // address = KEC(0xff || sender || salt || code_hash)[12:] -// -// Pre stack: sender, salt, code_hash, retdest +// Clobbers @SEGMENT_KERNEL_GENERAL. +// Pre stack: sender, code_hash, salt, retdest // Post stack: address global get_create2_address: - // stack: sender, salt, code_hash, retdest - // TODO: Replace with actual implementation. - %pop3 - PUSH 123 + // stack: sender, code_hash, salt, retdest + PUSH 0xff PUSH 0 %mstore_kernel_general + %stack (sender, code_hash, salt, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 1, sender, 20, get_create2_address_contd, salt, code_hash, retdest) + %jump(mstore_unpacking) +get_create2_address_contd: + POP + %stack (salt, code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 21, salt, 32, get_create2_address_contd2, code_hash, retdest) + %jump(mstore_unpacking) +get_create2_address_contd2: + POP + %stack (code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 53, code_hash, 32, get_create2_address_finish, retdest) + %jump(mstore_unpacking) +get_create2_address_finish: + POP + %stack (retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 0, 85, retdest) // context, segment, offset, len + KECCAK_GENERAL // stack: address, retdest + %mod_const(0x10000000000000000000000000000000000000000) // 2^160 %observe_new_address SWAP1 JUMP diff --git a/evm/src/cpu/kernel/tests/core/create_addresses.rs b/evm/src/cpu/kernel/tests/core/create_addresses.rs index 03d780d8..3f316578 100644 --- a/evm/src/cpu/kernel/tests/core/create_addresses.rs +++ b/evm/src/cpu/kernel/tests/core/create_addresses.rs @@ -1,6 +1,9 @@ +use std::str::FromStr; + use anyhow::Result; -use ethereum_types::U256; +use ethereum_types::{H256, U256}; use hex_literal::hex; +use keccak_hash::keccak; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -24,22 +27,89 @@ fn test_get_create_address() -> Result<()> { Ok(()) } +struct Create2TestCase { + code_hash: H256, + salt: U256, + sender: U256, + expected_addr: U256, +} + +/// Taken from https://eips.ethereum.org/EIPS/eip-1014 +fn create2_test_cases() -> Vec { + vec![ + Create2TestCase { + code_hash: keccak(hex!("00")), + salt: U256::zero(), + sender: U256::zero(), + expected_addr: U256::from_str("0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38").unwrap(), + }, + Create2TestCase { + code_hash: keccak(hex!("00")), + salt: U256::zero(), + sender: U256::from_str("0xdeadbeef00000000000000000000000000000000").unwrap(), + expected_addr: U256::from_str("0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3").unwrap(), + }, + Create2TestCase { + code_hash: keccak(hex!("00")), + salt: U256::from_str( + "0x000000000000000000000000feed000000000000000000000000000000000000", + ) + .unwrap(), + sender: U256::from_str("0xdeadbeef00000000000000000000000000000000").unwrap(), + expected_addr: U256::from_str("0xD04116cDd17beBE565EB2422F2497E06cC1C9833").unwrap(), + }, + Create2TestCase { + code_hash: keccak(hex!("deadbeef")), + salt: U256::zero(), + sender: U256::zero(), + expected_addr: U256::from_str("0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e").unwrap(), + }, + Create2TestCase { + code_hash: keccak(hex!("deadbeef")), + salt: U256::from_str( + "0x00000000000000000000000000000000000000000000000000000000cafebabe", + ) + .unwrap(), + sender: U256::from_str("0x00000000000000000000000000000000deadbeef").unwrap(), + expected_addr: U256::from_str("0x60f3f640a8508fC6a86d45DF051962668E1e8AC7").unwrap(), + }, + Create2TestCase { + code_hash: keccak(hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")), + salt: U256::from_str( + "0x00000000000000000000000000000000000000000000000000000000cafebabe", + ) + .unwrap(), + sender: U256::from_str("0x00000000000000000000000000000000deadbeef").unwrap(), + expected_addr: U256::from_str("0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C").unwrap(), + }, + Create2TestCase { + code_hash: keccak(hex!("")), + salt: U256::zero(), + sender: U256::zero(), + expected_addr: U256::from_str("0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0").unwrap(), + }, + ] +} + #[test] fn test_get_create2_address() -> Result<()> { let get_create2_address = KERNEL.global_labels["get_create2_address"]; - // TODO: Replace with real data once we have a real implementation. let retaddr = 0xdeadbeefu32.into(); - let code_hash = 0.into(); - let salt = 5.into(); - let sender = 0.into(); - let expected_addr = 123.into(); - let initial_stack = vec![retaddr, code_hash, salt, sender]; - let mut interpreter = Interpreter::new_with_kernel(get_create2_address, initial_stack); - interpreter.run()?; + for Create2TestCase { + code_hash, + salt, + sender, + expected_addr, + } in create2_test_cases() + { + let initial_stack = vec![retaddr, salt, U256::from(code_hash.0), sender]; + let mut interpreter = Interpreter::new_with_kernel(get_create2_address, initial_stack); + interpreter.run()?; - assert_eq!(interpreter.stack(), &[expected_addr]); + assert_eq!(interpreter.stack(), &[expected_addr]); + } Ok(()) } From f4e65feb65b74620f8c664ae82f8e68ee6f0370e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 22 Mar 2023 19:14:55 +0100 Subject: [PATCH 2/3] Fix bugs in `wcopy` and `update_mem_words` (#934) * Fix bugs in wcopy and update_mem_words * Update comment --- evm/src/cpu/kernel/asm/memory/metadata.asm | 6 +++++- evm/src/cpu/kernel/asm/memory/syscalls.asm | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index d891c0d1..1c526c2d 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -201,7 +201,7 @@ global sys_basefee: // stack: old_num_words, num_words, kexit_info DUP2 DUP2 GT // stack: old_num_words > num_words, old_num_words, num_words, kexit_info - %jumpi(%%end) + %jumpi(%%no_update) // stack: old_num_words, num_words, kexit_info %memory_cost // stack: old_cost, num_words, kexit_info @@ -214,6 +214,10 @@ global sys_basefee: SUB // stack: additional_cost, kexit_info %charge_gas + %jump(%%end) +%%no_update: + // stack: old_num_words, num_words, kexit_info + %pop2 %%end: // stack: kexit_info %endmacro diff --git a/evm/src/cpu/kernel/asm/memory/syscalls.asm b/evm/src/cpu/kernel/asm/memory/syscalls.asm index 11f8054b..86435408 100644 --- a/evm/src/cpu/kernel/asm/memory/syscalls.asm +++ b/evm/src/cpu/kernel/asm/memory/syscalls.asm @@ -124,14 +124,14 @@ sys_calldataload_after_mload_packing: // stack: kexit_info, dest_offset, offset, size DUP4 %num_bytes_to_num_words %mul_const(@GAS_COPY) %add_const(@GAS_VERYLOW) %charge_gas - %stack (kexit_info, dest_offset, offset, size) -> (dest_offset, size, dest_offset, offset, size, kexit_info) + %stack (kexit_info, dest_offset, offset, size) -> (dest_offset, size, kexit_info, dest_offset, offset, size) ADD // TODO: check for overflow, see discussion here https://github.com/mir-protocol/plonky2/pull/930/files/a4ea0965d79561c345e2f77836c07949c7e0bc69#r1143630253 - // stack: expanded_num_bytes, dest_offset, offset, size, kexit_info + // stack: expanded_num_bytes, kexit_info, dest_offset, offset, size, kexit_info DUP1 %ensure_reasonable_offset %update_mem_bytes GET_CONTEXT - %stack (context, dest_offset, offset, size, kexit_info) -> + %stack (context, kexit_info, dest_offset, offset, size) -> (context, @SEGMENT_MAIN_MEMORY, dest_offset, context, $segment, offset, size, %%after, kexit_info) %jump(memcpy) %%after: From 0650d2636c337abece38cadb317c6fdee706f2b4 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Wed, 22 Mar 2023 17:26:14 -0700 Subject: [PATCH 3/3] remove .scale --- evm/src/bn254_pairing.rs | 4 +-- evm/src/extension_tower.rs | 69 ++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/evm/src/bn254_pairing.rs b/evm/src/bn254_pairing.rs index 08eb614c..7277c2a8 100644 --- a/evm/src/bn254_pairing.rs +++ b/evm/src/bn254_pairing.rs @@ -69,14 +69,14 @@ pub fn miller_loop(p: Curve, q: TwistedCurve) -> Fp12 { pub fn tangent(p: Curve, q: TwistedCurve) -> Fp12 { let cx = -BN254::new(3) * p.x * p.x; let cy = BN254::new(2) * p.y; - sparse_embed(p.y * p.y - BN254::new(9), q.x.scale(cx), q.y.scale(cy)) + sparse_embed(p.y * p.y - BN254::new(9), q.x * cx, q.y * cy) } /// The sloped line function for adding two points pub fn cord(p1: Curve, p2: Curve, q: TwistedCurve) -> Fp12 { let cx = p2.y - p1.y; let cy = p1.x - p2.x; - sparse_embed(p1.y * p2.x - p2.y * p1.x, q.x.scale(cx), q.y.scale(cy)) + sparse_embed(p1.y * p2.x - p2.y * p1.x, q.x * cx, q.y * cy) } /// The tangent and cord functions output sparse Fp12 elements. diff --git a/evm/src/extension_tower.rs b/evm/src/extension_tower.rs index 23c130a0..35bbefdd 100644 --- a/evm/src/extension_tower.rs +++ b/evm/src/extension_tower.rs @@ -6,8 +6,7 @@ use rand::distributions::{Distribution, Standard}; use rand::Rng; pub trait FieldExt: - Sized - + Copy + Copy + std::ops::Add + std::ops::Neg + std::ops::Sub @@ -317,15 +316,19 @@ impl Mul for Fp2 { } } -impl Fp2 { - /// This function scalar multiplies an Fp2 by an BN254 - pub fn scale(self, x: T) -> Self { +/// This function scalar multiplies an Fp2 by an Fp +impl Mul for Fp2 { + type Output = Fp2; + + fn mul(self, other: T) -> Self { Fp2 { - re: x * self.re, - im: x * self.im, + re: other * self.re, + im: other * self.im, } } +} +impl Fp2 { /// Return the complex conjugate z' of z: Fp2 /// This also happens to be the frobenius map /// z -> z^p @@ -357,7 +360,7 @@ impl FieldExt for Fp2 { /// The inverse of z is given by z'/||z||^2 since ||z||^2 = zz' fn inv(self) -> Fp2 { let norm_sq = self.norm_sq(); - self.conj().scale(norm_sq.inv()) + self.conj() * norm_sq.inv() } } @@ -880,17 +883,19 @@ where } } -impl Fp6 +/// This function scalar multiplies an Fp6 by an Fp2 +impl Mul> for Fp6 where T: FieldExt, Fp2: Adj, { - // This function scalar multiplies an Fp6 by an Fp2 - fn scale(self, x: Fp2) -> Fp6 { + type Output = Fp6; + + fn mul(self, other: Fp2) -> Self { Fp6 { - t0: x * self.t0, - t1: x * self.t1, - t2: x * self.t2, + t0: other * self.t0, + t1: other * self.t1, + t2: other * self.t2, } } } @@ -981,9 +986,9 @@ where let prod_13 = self.frob(1) * self.frob(3); let prod_135 = (prod_13 * self.frob(5)).t0; let phi = prod_135.norm_sq(); - let prod_odds_over_phi = prod_135.scale(phi.inv()); + let prod_odds_over_phi = prod_135 * phi.inv(); let prod_24 = prod_13.frob(1); - prod_24.scale(prod_odds_over_phi) + prod_24 * prod_odds_over_phi } } @@ -1044,10 +1049,10 @@ where let prod_1379 = prod_17 * prod_17.frob(2); let prod_odds = (prod_1379 * prod_17.frob(4)).t0; let phi = prod_odds.norm_sq(); - let prod_odds_over_phi = prod_odds.scale(phi.inv()); + let prod_odds_over_phi = prod_odds * phi.inv(); let prod_evens_except_six = prod_1379.frob(1); - let prod_except_six = prod_evens_except_six.scale(prod_odds_over_phi); - self.conj().scale(prod_except_six) + let prod_except_six = prod_evens_except_six * prod_odds_over_phi; + self.conj() * prod_except_six } } @@ -1126,19 +1131,27 @@ where } } +/// This function scalar multiplies an Fp12 by an Fp6 +impl Mul> for Fp12 +where + T: FieldExt, + Fp2: Adj, +{ + type Output = Fp12; + + fn mul(self, other: Fp6) -> Self { + Fp12 { + z0: other * self.z0, + z1: other * self.z1, + } + } +} + impl Fp12 where T: FieldExt, Fp2: Adj, { - // This function scalar multiplies an Fp12 by an Fp6 - fn scale(self, x: Fp6) -> Fp12 { - Fp12 { - z0: x * self.z0, - z1: x * self.z1, - } - } - fn conj(self) -> Fp12 { Fp12 { z0: self.z0, @@ -1161,7 +1174,7 @@ where let n = n % 12; Fp12 { z0: self.z0.frob(n), - z1: self.z1.frob(n).scale(Fp2::::FROB_Z[n]), + z1: self.z1.frob(n) * (Fp2::::FROB_Z[n]), } } }