Skip to content
This repository has been archived by the owner on Jan 8, 2025. It is now read-only.

Feat: add RIP-7212 to the list of precompiles Cairo1Helpers module #779

Merged
merged 7 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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()));
}
}
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
Loading