Skip to content

Commit

Permalink
Merge branch 'dict-manager' of github.com:lambdaclass/cairo-rs-py int…
Browse files Browse the repository at this point in the history
…o squash-dict-add-test-tags
  • Loading branch information
Juan-M-V committed Nov 18, 2022
2 parents e161553 + 255bc69 commit a649c7a
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ default = ["pyo3/num-bigint", "pyo3/auto-initialize"]

[dependencies]
pyo3 = { version = "0.16.5" }
cairo-rs = { git = "https://github.com/lambdaclass/cairo-rs.git", rev = "4f36aaf46dea8cac158d0da5e80537388e048c01" }
cairo-rs = { git = "https://github.com/lambdaclass/cairo-rs.git", rev = "2ddf78e20cc25e660263a0c9c1b942780d95a0e6" }
num-bigint = "0.4"
lazy_static = "1.4.0"

Expand Down
27 changes: 27 additions & 0 deletions cairo_programs/ecdsa.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
%builtins output pedersen ecdsa

from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin
from starkware.cairo.common.hash import hash2
from starkware.cairo.common.signature import verify_ecdsa_signature

func main{output_ptr : felt*, pedersen_ptr : HashBuiltin*, ecdsa_ptr : SignatureBuiltin*}():
alloc_locals

let your_eth_addr = 874739451078007766457464989774322083649278607533249481151382481072868806602
let signature_r = 1839793652349538280924927302501143912227271479439798783640887258675143576352
let signature_s = 1819432147005223164874083361865404672584671743718628757598322238853218813979
let msg = 0000000000000000000000000000000000000000000000000000000000000002

verify_ecdsa_signature(
msg,
your_eth_addr,
signature_r,
signature_s,
)


assert [output_ptr] = your_eth_addr
let output_ptr = output_ptr + 1

return ()
end
2 changes: 1 addition & 1 deletion comparer_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def new_runner(program_name: str):

if __name__ == "__main__":
program_name = sys.argv[1]
if program_name in ["blake2s_felt", "blake2s_finalize", "blake2s_integration_tests", "blake2s_hello_world_hash", "dict_squash", "squash_dict", "dict_write"]:
if program_name in ["blake2s_felt", "blake2s_finalize", "blake2s_integration_tests", "blake2s_hello_world_hash", "dict_squash", "squash_dict", "dict_write", "dict_read", "dict_update"]:
pass
else:
new_runner(program_name)
Expand Down
1 change: 1 addition & 0 deletions hints_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,5 @@ def test_program(program_name: str):
test_program("blake2s_finalize")
test_program("blake2s_felt")
test_program("blake2s_integration_tests")
test_program("ecdsa")
print("\nAll test have passed")
50 changes: 50 additions & 0 deletions src/cairo_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,13 @@ impl PyCairoRunner {
.collect::<Vec<_>>()
.to_object(py))
}

/// Add (or replace if already present) a custom hash builtin.
/// Returns a Relocatable with the new hash builtin base.
pub fn add_additional_hash_builtin(&self) -> PyRelocatable {
let mut vm = (*self.pyvm.vm).borrow_mut();
self.inner.add_additional_hash_builtin(&mut vm).into()
}
}

#[pyclass]
Expand Down Expand Up @@ -1221,6 +1228,10 @@ mod test {
segment_index: 6,
offset: 0,
})],
vec![RelocatableValue(PyRelocatable {
segment_index: 7,
offset: 0,
})],
];

Python::with_gil(|py| {
Expand Down Expand Up @@ -1522,4 +1533,43 @@ mod test {
);
});
}

/// Test that add_additional_hash_builtin() returns successfully.
#[test]
fn add_additional_hash_builtin() {
Python::with_gil(|_| {
let program = fs::read_to_string("cairo_programs/fibonacci.json").unwrap();
let runner = PyCairoRunner::new(
program,
Some("main".to_string()),
Some("small".to_string()),
false,
)
.unwrap();

let expected_relocatable = PyRelocatable {
segment_index: 0,
offset: 0,
};
let relocatable = runner.add_additional_hash_builtin();
assert_eq!(expected_relocatable, relocatable);

assert_eq!(
(*runner.pyvm.vm)
.borrow()
.get_builtin_runners()
.last()
.map(|(key, _)| key.as_str()),
Some("hash_builtin"),
);

let mut vm = (*runner.pyvm.vm).borrow_mut();
// Check that the segment exists by writing to it.
vm.insert_value(
&Relocatable::from((0, 0)),
MaybeRelocatable::Int(bigint!(42)),
)
.expect("memory insert failed");
});
}
}
57 changes: 57 additions & 0 deletions src/ecdsa.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::collections::HashMap;

use cairo_rs::{
types::relocatable::Relocatable,
vm::{errors::vm_errors::VirtualMachineError, runners::builtin_runner::SignatureBuiltinRunner},
};

use num_bigint::BigInt;
use pyo3::prelude::*;

use crate::relocatable::PyRelocatable;

#[pyclass(name = "Signature")]
#[derive(Clone, Debug)]
pub struct PySignature {
signatures: HashMap<PyRelocatable, (BigInt, BigInt)>,
}

#[pymethods]
impl PySignature {
#[new]
pub fn new() -> Self {
Self {
signatures: HashMap::new(),
}
}

pub fn add_signature(&mut self, address: PyRelocatable, pair: (BigInt, BigInt)) {
self.signatures.insert(address, pair);
}
}

impl PySignature {
pub fn update_signature(
&self,
signature_builtin: &mut SignatureBuiltinRunner,
) -> Result<(), VirtualMachineError> {
for (address, pair) in self.signatures.iter() {
signature_builtin
.add_signature(Relocatable::from(address), pair)
.map_err(VirtualMachineError::MemoryError)?
}
Ok(())
}
}

impl Default for PySignature {
fn default() -> Self {
Self::new()
}
}

impl ToPyObject for PySignature {
fn to_object(&self, py: Python<'_>) -> PyObject {
self.clone().into_py(py)
}
}
11 changes: 4 additions & 7 deletions src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,14 @@ impl PyIds {
struct_types: Rc::clone(&self.struct_types),
}
.into_py(py));
}

if self
} else if self
.struct_types
.contains_key(cairo_type.trim_end_matches('*'))
{
let addr =
compute_addr_from_reference(hint_ref, &self.vm.borrow(), &self.ap_tracking)?;

let dereferenced_addr = self
let hint_value = self
.vm
.borrow()
.get_relocatable(&addr)
Expand All @@ -114,7 +112,7 @@ impl PyIds {

return Ok(PyTypedId {
vm: self.vm.clone(),
hint_value: dereferenced_addr,
hint_value,
cairo_type: cairo_type.trim_end_matches('*').to_string(),
struct_types: Rc::clone(&self.struct_types),
}
Expand Down Expand Up @@ -179,11 +177,10 @@ pub struct PyTypedId {
impl PyTypedId {
#[getter]
fn __getattr__(&self, py: Python, name: &str) -> PyResult<PyObject> {
let struct_type = self.struct_types.get(&self.cairo_type).unwrap();

if name == "address_" {
return Ok(PyMaybeRelocatable::from(self.hint_value.clone()).to_object(py));
}
let struct_type = self.struct_types.get(&self.cairo_type).unwrap();

match struct_type.get(name) {
Some(member) => {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod cairo_run;
pub mod cairo_runner;
mod dict_manager;
mod ecdsa;
pub mod ids;
mod memory;
mod memory_segments;
Expand Down
116 changes: 115 additions & 1 deletion src/memory.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use crate::{
relocatable::{PyMaybeRelocatable, PyRelocatable},
utils::to_py_error,
vm_core::PyVM,
};
use cairo_rs::{
types::relocatable::{MaybeRelocatable, Relocatable},
vm::vm_core::VirtualMachine,
};
use num_bigint::BigInt;
use pyo3::{
exceptions::{PyTypeError, PyValueError},
prelude::*,
};
use std::{cell::RefCell, rc::Rc};
use std::{borrow::Cow, cell::RefCell, rc::Rc};

const MEMORY_GET_ERROR_MSG: &str = "Failed to get value from Cairo memory";
const MEMORY_SET_ERROR_MSG: &str = "Failed to set value to Cairo memory";
Expand Down Expand Up @@ -69,6 +71,18 @@ impl PyMemory {
.collect::<Vec<PyMaybeRelocatable>>()
.to_object(py))
}

/// Return a continuous section of memory as a vector of integers.
pub fn get_range_as_ints(&self, addr: PyRelocatable, size: usize) -> PyResult<Vec<BigInt>> {
Ok(self
.vm
.borrow()
.get_integer_range(&Relocatable::from(&addr), size)
.map_err(to_py_error)?
.into_iter()
.map(Cow::into_owned)
.collect())
}
}

#[cfg(test)]
Expand Down Expand Up @@ -282,4 +296,104 @@ assert memory[ap] == fp
assert_eq!(range.unwrap_err(), expected_error);
});
}

// Test that get_range_as_ints() works as intended.
#[test]
fn get_range_as_ints() {
let vm = PyVM::new(
BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]),
false,
);
let memory = PyMemory::new(&vm);

let addr = {
let mut vm = vm.vm.borrow_mut();
let addr = vm.add_memory_segment();

vm.load_data(
&MaybeRelocatable::from(&addr),
vec![
bigint!(1).into(),
bigint!(2).into(),
bigint!(3).into(),
bigint!(4).into(),
],
)
.expect("memory insertion failed");

addr
};

assert_eq!(
memory
.get_range_as_ints(addr.into(), 4)
.expect("get_range_as_ints() failed"),
vec![bigint!(1), bigint!(2), bigint!(3), bigint!(4)],
);
}

// Test that get_range_as_ints() fails when not all values are integers.
#[test]
fn get_range_as_ints_mixed() {
let vm = PyVM::new(
BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]),
false,
);
let memory = PyMemory::new(&vm);

let addr = {
let mut vm = vm.vm.borrow_mut();
let addr = vm.add_memory_segment();

vm.load_data(
&MaybeRelocatable::from(&addr),
vec![
bigint!(1).into(),
bigint!(2).into(),
MaybeRelocatable::RelocatableValue((1, 2).into()),
bigint!(4).into(),
],
)
.expect("memory insertion failed");

addr
};

memory
.get_range_as_ints(addr.into(), 4)
.expect_err("get_range_as_ints() succeeded (should have failed)");
}

// Test that get_range_as_ints() fails when the requested range is larger than the available
// segments.
#[test]
fn get_range_as_ints_incomplete() {
let vm = PyVM::new(
BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]),
false,
);
let memory = PyMemory::new(&vm);

let addr = {
let mut vm = vm.vm.borrow_mut();
let addr = vm.add_memory_segment();

vm.load_data(
&MaybeRelocatable::from(&addr),
vec![
bigint!(1).into(),
bigint!(2).into(),
bigint!(3).into(),
bigint!(4).into(),
],
)
.expect("memory insertion failed");

addr
};

memory
.get_range_as_ints(addr.into(), 8)
.expect_err("get_range_as_ints() succeeded (should have failed)");
}
}
2 changes: 1 addition & 1 deletion src/relocatable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub enum PyMaybeRelocatable {
}

#[pyclass(name = "Relocatable")]
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PyRelocatable {
#[pyo3(get)]
pub segment_index: isize,
Expand Down
Loading

0 comments on commit a649c7a

Please sign in to comment.