Skip to content
Open
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
63 changes: 63 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ arbitrary = { workspace = true, features = ["derive"], optional = true }

# Used to derive clap traits for CLIs
clap = { version = "4.3.10", features = ["derive"], optional = true}
ark-secp256k1 = "0.4.0"

[dev-dependencies]
assert_matches = "1.5.0"
Expand Down
90 changes: 89 additions & 1 deletion vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,101 @@ impl Cairo1HintProcessor {
t_or_k0,
t_or_k1,
),

Hint::Starknet(cairo_lang_casm::hints::StarknetHint::SystemCall { system }) => {
Ok(self.execute_syscall(system, vm, exec_scopes)?)
}
hint => Err(HintError::UnknownHint(
format!("{:?}", hint).into_boxed_str(),
)),
}
}

/// Executes a syscall.
fn execute_syscall(
&self,
system: &ResOperand,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
) -> Result<(), HintError> {
let system_ptr = as_relocatable(vm, system)?;
let mut system_buffer = super::memory_buffer::MemBuffer::new(vm, system_ptr);
let selector = system_buffer.next_felt252()?.to_bytes_be();
let mut gas_counter = system_buffer.next_usize()?;
let mut execute_handle_helper =
|handler: &mut dyn FnMut(
// The syscall buffer.
&mut super::memory_buffer::MemBuffer<'_>,
// The gas counter.
&mut usize,
)
-> Result<super::syscall::SyscallResult, HintError>| {
match handler(&mut system_buffer, &mut gas_counter)? {
super::syscall::SyscallResult::Success(values) => {
system_buffer.write(gas_counter)?;
system_buffer.write(Felt252::from(0))?;
system_buffer.write_data(values.into_iter())?;
}
super::syscall::SyscallResult::Failure(revert_reason) => {
println!("syscall failed!");
system_buffer.write(gas_counter)?;
system_buffer.write(Felt252::from(1))?;
system_buffer.write_arr(revert_reason.into_iter())?;
}
}
Ok(())
};
let selector = std::str::from_utf8(&selector)
.unwrap()
.trim_start_matches('\0');
// *self
// .syscalls_used_resources
// .syscalls
// .entry(selector.into())
// .or_default() += 1;
match selector {
"Secp256k1New" => execute_handle_helper(&mut |system_buffer, gas_counter| {
super::syscall::secp256k1_new(
gas_counter,
system_buffer.next_u256()?,
system_buffer.next_u256()?,
exec_scopes,
)
}),
"Secp256k1Add" => execute_handle_helper(&mut |system_buffer, gas_counter| {
super::syscall::secp256k1_add(
gas_counter,
exec_scopes,
system_buffer.next_usize()?,
system_buffer.next_usize()?,
)
}),
"Secp256k1Mul" => execute_handle_helper(&mut |system_buffer, gas_counter| {
super::syscall::secp256k1_mul(
gas_counter,
system_buffer.next_usize()?,
system_buffer.next_u256()?,
exec_scopes,
)
}),
"Secp256k1GetPointFromX" => execute_handle_helper(&mut |system_buffer, gas_counter| {
super::syscall::secp256k1_get_point_from_x(
gas_counter,
system_buffer.next_u256()?,
system_buffer.next_bool()?,
exec_scopes,
)
}),
"Secp256k1GetXy" => execute_handle_helper(&mut |system_buffer, gas_counter| {
super::syscall::secp256k1_get_xy(
gas_counter,
system_buffer.next_usize()?,
exec_scopes,
)
}),
_ => panic!("Unknown selector for system call!"),
}
}

fn alloc_segment(&self, vm: &mut VirtualMachine, dst: &CellRef) -> Result<(), HintError> {
let segment = vm.add_memory_segment();
vm.insert_value(cell_ref_to_relocatable(dst, vm)?, segment)
Expand Down
141 changes: 141 additions & 0 deletions vm/src/hint_processor/cairo_1_hint_processor/memory_buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use std::borrow::Cow;

use crate::types::relocatable::MaybeRelocatable;
use crate::vm::errors::memory_errors::MemoryError;
use crate::Felt252;
use crate::{types::relocatable::Relocatable, vm::vm_core::VirtualMachine};
use num_bigint::BigUint;
use num_traits::ToPrimitive;
use num_traits::Zero;
use std::ops::Shl;

/// A helper struct to continuously write and read from a buffer in the VM memory.
pub struct MemBuffer<'a> {
/// The VM to write to.
/// This is a trait so that we would borrow the actual VM only once.
vm: &'a mut VirtualMachine,
/// The current location of the buffer.
pub ptr: Relocatable,
}
impl<'a> MemBuffer<'a> {
/// Creates a new buffer.
pub fn new(vm: &'a mut VirtualMachine, ptr: Relocatable) -> Self {
Self { vm, ptr }
}

/// Creates a new segment and returns a buffer wrapping it.
pub fn new_segment(vm: &'a mut VirtualMachine) -> Self {
let ptr = vm.add_memory_segment();
Self::new(vm, ptr)
}

/// Returns the current position of the buffer and advances it by one.
fn next(&mut self) -> Relocatable {
let ptr = self.ptr;
self.ptr += 1;
ptr
}

/// Returns the felt252 value in the current position of the buffer and advances it by one.
/// Fails if the value is not a felt252.
/// Borrows the buffer since a reference is returned.
pub fn next_felt252(&mut self) -> Result<Cow<'_, Felt252>, MemoryError> {
let ptr = self.next();
self.vm.get_integer(ptr)
}

/// Returns the bool value in the current position of the buffer and advances it by one.
/// Fails with `MemoryError` if the value is not a felt252.
/// Panics if the value is not a bool.
pub fn next_bool(&mut self) -> Result<bool, MemoryError> {
let ptr = self.next();
Ok(!(self.vm.get_integer(ptr)?.is_zero()))
}

/// Returns the usize value in the current position of the buffer and advances it by one.
/// Fails with `MemoryError` if the value is not a felt252.
/// Panics if the value is not a usize.
pub fn next_usize(&mut self) -> Result<usize, MemoryError> {
Ok(self.next_felt252()?.to_usize().unwrap())
}

/// Returns the u128 value in the current position of the buffer and advances it by one.
/// Fails with `MemoryError` if the value is not a felt252.
/// Panics if the value is not a u128.
pub fn next_u128(&mut self) -> Result<u128, MemoryError> {
Ok(self.next_felt252()?.to_u128().unwrap())
}

/// Returns the u64 value in the current position of the buffer and advances it by one.
/// Fails with `MemoryError` if the value is not a felt252.
/// Panics if the value is not a u64.
#[allow(unused)]
pub fn next_u64(&mut self) -> Result<u64, MemoryError> {
Ok(self.next_felt252()?.to_u64().unwrap())
}

/// Returns the u256 value encoded starting from the current position of the buffer and advances
/// it by two.
/// Fails with `MemoryError` if any of the next two values are not felt252s.
/// Panics if any of the next two values are not u128.
pub fn next_u256(&mut self) -> Result<BigUint, MemoryError> {
Ok(self.next_u128()? + BigUint::from(self.next_u128()?).shl(128))
}

/// Returns the address value in the current position of the buffer and advances it by one.
/// Fails if the value is not an address.
#[allow(unused)]
pub fn next_addr(&mut self) -> Result<Relocatable, MemoryError> {
let ptr = self.next();
self.vm.get_relocatable(ptr)
}

// /// Returns the array of integer values pointed to by the two next addresses in the buffer and
// /// advances it by two. Will fail if the two values are not addresses or if the addresses do
// /// not point to an array of integers.
// pub fn next_arr(&mut self) -> Result<Vec<Felt252>, HintError> {
// let start = self.next_addr()?;
// let end = self.next_addr()?;
// vm_get_range(self.vm, start, end)
// }

/// Writes a value to the current position of the buffer and advances it by one.
pub fn write<T: Into<MaybeRelocatable>>(&mut self, value: T) -> Result<(), MemoryError> {
let ptr = self.next();
self.vm.insert_value(ptr, value)
}
/// Writes an iterator of values starting from the current position of the buffer and advances
/// it to after the end of the written value.
pub fn write_data<T: Into<MaybeRelocatable>, Data: Iterator<Item = T>>(
&mut self,
data: Data,
) -> Result<(), MemoryError> {
for value in data {
self.write(value)?;
}
Ok(())
}

/// Writes an array into a new segment and writes the start and end pointers to the current
/// position of the buffer. Advances the buffer by two.
pub fn write_arr<T: Into<MaybeRelocatable>, Data: Iterator<Item = T>>(
&mut self,
data: Data,
) -> Result<(), MemoryError> {
let (start, end) = segment_with_data(self.vm, data)?;
self.write(start)?;
self.write(end)
}
}

/// Creates a new segment in the VM memory and writes data to it, returning the start and end
/// pointers of the segment.
fn segment_with_data<T: Into<MaybeRelocatable>, Data: Iterator<Item = T>>(
vm: &mut VirtualMachine,
data: Data,
) -> Result<(Relocatable, Relocatable), MemoryError> {
let mut segment = MemBuffer::new_segment(vm);
let start = segment.ptr;
segment.write_data(data)?;
Ok((start, segment.ptr))
}
2 changes: 2 additions & 0 deletions vm/src/hint_processor/cairo_1_hint_processor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod dict_manager;
pub mod hint_processor;
pub mod hint_processor_utils;
mod memory_buffer;
mod syscall;
Loading