Skip to content

Commit

Permalink
Feat: add RIP-7212 to the list of precompiles Cairo1Helpers module (#779
Browse files Browse the repository at this point in the history
)

* first commit

* scarb fmt + corrected tests source

* removed unnecessary imports

* review corrections

* corrected address range

* modified tests deploy address

* changed contract address to random one
  • Loading branch information
Quentash authored Apr 19, 2024
1 parent 291e45a commit 4fbf682
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 62 deletions.
2 changes: 1 addition & 1 deletion crates/evm/src/call_helpers.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,5 @@ impl CallHelpersImpl of CallHelpers {
/// Check whether an address for a call-family opcode is a precompile.
fn is_precompile(self: EthAddress) -> bool {
let self: felt252 = self.into();
return (self != 0 && self.into() < 10_u256);
return (self != 0 && (self.into() < 10_u256 || self.into() == 256_u256));
}
84 changes: 47 additions & 37 deletions crates/evm/src/precompiles.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod blake2f;
mod ec_recover;
mod identity;
mod modexp;
mod p256verify;
mod sha256;

use core::traits::Into;
Expand All @@ -12,6 +13,7 @@ use evm::precompiles::blake2f::Blake2f;
use evm::precompiles::ec_recover::EcRecover;
use evm::precompiles::identity::Identity;
use evm::precompiles::modexp::ModExp;
use evm::precompiles::p256verify::P256Verify;
use evm::precompiles::sha256::Sha256;
use starknet::EthAddress;

Expand All @@ -27,43 +29,51 @@ impl PrecompilesImpl of Precompiles {
let precompile_address = vm.message.target.evm;
let input = vm.message().data;

let (gas, result) = match precompile_address.address {
0 => {
// we should never reach this branch!
panic!("pre-compile address can't be 0")
},
1 => { EcRecover::exec(input)? },
2 => { Sha256::exec(input)? },
3 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet", precompile_address.address
)
},
4 => { Identity::exec(input)? },
5 => { ModExp::exec(input)? },
6 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet", precompile_address.address
)
},
7 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet", precompile_address.address
)
},
8 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet", precompile_address.address
)
},
9 => { Blake2f::exec(input)? },
_ => {
// we should never reach this branch!
panic!("address {} isn't a pre-compile", precompile_address.address)
let (gas, result) = if precompile_address.address == 0x100 {
P256Verify::exec(input)?
} else {
match precompile_address.address {
0 => {
// we should never reach this branch!
panic!("pre-compile address can't be 0")
},
1 => { EcRecover::exec(input)? },
2 => { Sha256::exec(input)? },
3 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet",
precompile_address.address
)
},
4 => { Identity::exec(input)? },
5 => { ModExp::exec(input)? },
6 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet",
precompile_address.address
)
},
7 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet",
precompile_address.address
)
},
8 => {
// we should never reach this branch!
panic!(
"pre-compile at address {} isn't implemented yet",
precompile_address.address
)
},
9 => { Blake2f::exec(input)? },
_ => {
// we should never reach this branch!
panic!("address {} isn't a pre-compile", precompile_address.address)
}
}
};

Expand Down
67 changes: 67 additions & 0 deletions crates/evm/src/precompiles/p256verify.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use core::starknet::SyscallResultTrait;
use evm::errors::{EVMError};
use evm::precompiles::Precompile;
use starknet::{
EthAddress, eth_signature::{recover_public_key, public_key_point_to_eth_address, Signature},
secp256r1::{Secp256r1Point, secp256r1_new_syscall}, secp256_trait::is_valid_signature
};
use utils::helpers::{U256Trait, ToBytes, FromBytes};

const P256VERIFY_PRECOMPILE_GAS_COST: u128 = 3450;

impl P256Verify of Precompile {
#[inline(always)]
fn address() -> EthAddress {
EthAddress { address: 0x100 }
}

fn exec(input: Span<u8>) -> Result<(u128, Span<u8>), EVMError> {
let gas: u128 = P256VERIFY_PRECOMPILE_GAS_COST;

if input.len() != 160 {
return Result::Ok((gas, array![0].span()));
}

let message_hash = input.slice(0, 32);
let message_hash = match message_hash.from_be_bytes() {
Option::Some(message_hash) => message_hash,
Option::None => { return Result::Ok((gas, array![].span())); }
};

let r: Option<u256> = input.slice(32, 32).from_be_bytes();
let r = match r {
Option::Some(r) => r,
Option::None => { return Result::Ok((gas, array![].span())); }
};

let s: Option<u256> = input.slice(64, 32).from_be_bytes();
let s = match s {
Option::Some(s) => s,
Option::None => { return Result::Ok((gas, array![].span())); }
};

let x: Option<u256> = input.slice(96, 32).from_be_bytes();
let x = match x {
Option::Some(x) => x,
Option::None => { return Result::Ok((gas, array![].span())); }
};

let y: Option<u256> = input.slice(128, 32).from_be_bytes();
let y = match y {
Option::Some(y) => y,
Option::None => { return Result::Ok((gas, array![].span())); }
};

let public_key: Option<Secp256r1Point> = secp256r1_new_syscall(x, y).unwrap_syscall();
let public_key = match public_key {
Option::Some(public_key) => public_key,
Option::None => { return Result::Ok((gas, array![].span())); }
};

if !is_valid_signature(message_hash, r, s, public_key) {
return Result::Ok((gas, array![0].span()));
}

return Result::Ok((gas, array![1].span()));
}
}
60 changes: 36 additions & 24 deletions crates/evm/src/tests/test_instructions/test_system_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ fn test_exec_call() {
kakarot_core.deploy_externally_owned_account(evm_address);

// Set vm bytecode
// (call 0xffffff 0x100 0 0 0 0 1)
// (call 0xffffff 0xabfa740ccd 0 0 0 0 1)
let bytecode = array![
0x60,
0x01,
Expand All @@ -107,9 +107,12 @@ fn test_exec_call() {
0x00,
0x60,
0x00,
0x61,
0x01,
0x00,
0x64,
0xab,
0xfa,
0x74,
0x0c,
0xcd,
0x62,
0xff,
0xff,
Expand All @@ -122,13 +125,13 @@ fn test_exec_call() {

let mut vm = VMBuilderTrait::new_with_presets().with_bytecode(bytecode).build();

// Deploy bytecode at 0x100
// Deploy bytecode at 0xabfa740ccd
// ret (+ 0x1 0x1)
let deployed_bytecode = array![
0x60, 0x01, 0x60, 0x01, 0x01, 0x60, 0x00, 0x53, 0x60, 0x20, 0x60, 0x00, 0xf3
]
.span();
let eth_address: EthAddress = 0x100_u256.into();
let eth_address: EthAddress = 0xabfa740ccd_u256.into();
initialize_contract_account(eth_address, deployed_bytecode, Default::default().span())
.expect('set code failed');

Expand All @@ -150,7 +153,7 @@ fn test_exec_call_no_return() {
kakarot_core.deploy_externally_owned_account(evm_address);

// Set vm bytecode
// (call 0xffffff 0x100 0 0 0 0 1)
// (call 0xffffff 0xabfa740ccd 0 0 0 0 1)
let bytecode = array![
0x60,
0x01,
Expand All @@ -162,9 +165,12 @@ fn test_exec_call_no_return() {
0x00,
0x60,
0x00,
0x61,
0x01,
0x00,
0x64,
0xab,
0xfa,
0x74,
0x0c,
0xcd,
0x62,
0xff,
0xff,
Expand All @@ -177,10 +183,10 @@ fn test_exec_call_no_return() {

let mut vm = VMBuilderTrait::new_with_presets().with_bytecode(bytecode).build();

// Deploy bytecode at 0x100
// Deploy bytecode at 0xabfa740ccd
// (+ 0x1 0x1)
let deployed_bytecode = array![0x60, 0x01, 0x60, 0x01, 0x01, 0x60, 0x00, 0x53, 0x00].span();
let eth_address: EthAddress = 0x100_u256.into();
let eth_address: EthAddress = 0xabfa740ccd_u256.into();
initialize_contract_account(eth_address, deployed_bytecode, Default::default().span())
.expect('set code failed');

Expand All @@ -202,7 +208,7 @@ fn test_exec_staticcall() {
kakarot_core.deploy_externally_owned_account(evm_address);

// Set vm bytecode
// (call 0xffffff 0x100 0 0 0 0 1)
// (call 0xffffff 0xabfa740ccd 0 0 0 0 1)
let bytecode = array![
0x60,
0x01,
Expand All @@ -212,9 +218,12 @@ fn test_exec_staticcall() {
0x00,
0x60,
0x00,
0x61,
0x01,
0x00,
0x64,
0xab,
0xfa,
0x74,
0x0c,
0xcd,
0x62,
0xff,
0xff,
Expand All @@ -226,13 +235,13 @@ fn test_exec_staticcall() {
.span();

let mut vm = VMBuilderTrait::new_with_presets().with_bytecode(bytecode).build();
// Deploy bytecode at 0x100
// Deploy bytecode at 0xabfa740ccd
// ret (+ 0x1 0x1)
let deployed_bytecode = array![
0x60, 0x01, 0x60, 0x01, 0x01, 0x60, 0x00, 0x53, 0x60, 0x20, 0x60, 0x00, 0xf3
]
.span();
let eth_address: EthAddress = 0x100_u256.into();
let eth_address: EthAddress = 0xabfa740ccd_u256.into();
initialize_contract_account(eth_address, deployed_bytecode, Default::default().span())
.expect('set code failed');

Expand All @@ -254,7 +263,7 @@ fn test_exec_staticcall_no_return() {
kakarot_core.deploy_externally_owned_account(evm_address);

// Set vm bytecode
// (call 0xffffff 0x100 0 0 0 0 1)
// (call 0xffffff 0xabfa740ccd 0 0 0 0 1)
let bytecode = array![
0x60,
0x01,
Expand All @@ -266,9 +275,12 @@ fn test_exec_staticcall_no_return() {
0x00,
0x60,
0x00,
0x61,
0x01,
0x00,
0x64,
0xab,
0xfa,
0x74,
0x0c,
0xcd,
0x62,
0xff,
0xff,
Expand All @@ -281,10 +293,10 @@ fn test_exec_staticcall_no_return() {

let mut vm = VMBuilderTrait::new_with_presets().with_bytecode(bytecode).build();

// Deploy bytecode at 0x100
// Deploy bytecode at 0xabfa740ccd
// (+ 0x1 0x1)
let deployed_bytecode = array![0x60, 0x01, 0x60, 0x01, 0x01, 0x60, 0x00, 0x53, 0x00].span();
let eth_address: EthAddress = 0x100_u256.into();
let eth_address: EthAddress = 0xabfa740ccd_u256.into();
initialize_contract_account(eth_address, deployed_bytecode, Default::default().span())
.expect('set code failed');

Expand Down
1 change: 1 addition & 0 deletions crates/evm/src/tests/test_precompiles.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ mod test_data;
mod test_ec_recover;
mod test_identity;
mod test_modexp;
mod test_p256verify;
mod test_sha256;
Loading

0 comments on commit 4fbf682

Please sign in to comment.