diff --git a/Cargo.lock b/Cargo.lock index b6e47e47b..08e592193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -423,7 +423,7 @@ dependencies = [ [[package]] name = "cairo-vm" version = "2.0.0-rc4" -source = "git+https://github.com/kkrt-labs/cairo-vm?rev=12c5b64ec4f1ee1fb8cfef4978267fb23f6bacce#12c5b64ec4f1ee1fb8cfef4978267fb23f6bacce" +source = "git+https://github.com/kkrt-labs/cairo-vm?rev=7e0e13708d2265fadc913692709737b50908b97c#7e0e13708d2265fadc913692709737b50908b97c" dependencies = [ "anyhow", "arbitrary", diff --git a/Cargo.toml b/Cargo.toml index 81e416590..ff9411720 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,4 +57,4 @@ cairo-vm = { git = "https://github.com/lambdaclass/cairo-vm.git", tag = "v2.0.0- ] } [patch."https://github.com/lambdaclass/cairo-vm.git"] -cairo-vm = { git = "https://github.com/kkrt-labs/cairo-vm", rev = "12c5b64ec4f1ee1fb8cfef4978267fb23f6bacce" } +cairo-vm = { git = "https://github.com/kkrt-labs/cairo-vm", rev = "7e0e13708d2265fadc913692709737b50908b97c" } diff --git a/cairo/tests/ethereum/cancun/test_trie.py b/cairo/tests/ethereum/cancun/test_trie.py index 6f333868a..5d6194a51 100644 --- a/cairo/tests/ethereum/cancun/test_trie.py +++ b/cairo/tests/ethereum/cancun/test_trie.py @@ -27,7 +27,7 @@ ) from ethereum_types.bytes import Bytes, Bytes32 from ethereum_types.numeric import U256, Uint -from hypothesis import example, given +from hypothesis import Verbosity, example, given, settings from hypothesis import strategies as st from cairo_addons.testing.errors import cairo_error, strict_raises @@ -79,6 +79,7 @@ def test_common_prefix_length(self, cairo_run, a: Bytes, b: Bytes): assert common_prefix_length(a, b) == cairo_run("common_prefix_length", a, b) @given(a=..., b=...) + @settings(verbosity=Verbosity.quiet) def test_common_prefix_length_should_fail( self, cairo_programs, cairo_run_py, a: Bytes, b: Bytes ): @@ -101,6 +102,7 @@ def test_nibble_list_to_compact(self, cairo_run, x, is_leaf: bool): ) @given(x=nibble.filter(lambda x: len(x) != 0), is_leaf=...) + @settings(verbosity=Verbosity.quiet) def test_nibble_list_to_compact_should_raise_when_wrong_remainder( self, cairo_programs, cairo_run_py, x, is_leaf: bool ): diff --git a/cairo/tests/ethereum/cancun/vm/precompiled_contracts/test_mapping.py b/cairo/tests/ethereum/cancun/vm/precompiled_contracts/test_mapping.py index 78dc2f3af..81048ddc4 100644 --- a/cairo/tests/ethereum/cancun/vm/precompiled_contracts/test_mapping.py +++ b/cairo/tests/ethereum/cancun/vm/precompiled_contracts/test_mapping.py @@ -2,7 +2,7 @@ ECRECOVER_ADDRESS, PRE_COMPILED_CONTRACTS, ) -from hypothesis import example, given +from hypothesis import Verbosity, example, given, settings from hypothesis import strategies as st from cairo_addons.testing.errors import cairo_error @@ -27,6 +27,7 @@ def test_precompile_table_lookup_invalid_addresses(self, cairo_run, address_int) assert table_address == 0 @given(address=st.sampled_from(list(PRE_COMPILED_CONTRACTS.keys()))) + @settings(verbosity=Verbosity.quiet) def test_precompile_table_lookup_hint_index_out_of_bounds( self, cairo_programs, cairo_run_py, address ): @@ -42,6 +43,7 @@ def test_precompile_table_lookup_hint_index_out_of_bounds( cairo_run_py("precompile_table_lookup", address_int) @given(address=st.sampled_from(list(PRE_COMPILED_CONTRACTS.keys()))) + @settings(verbosity=Verbosity.quiet) def test_precompile_table_lookup_hint_index_different_address( self, cairo_programs, cairo_run_py, address ): diff --git a/cairo/tests/legacy/utils/test_bytes_legacy.py b/cairo/tests/legacy/utils/test_bytes_legacy.py index 609c12255..4bac6187a 100644 --- a/cairo/tests/legacy/utils/test_bytes_legacy.py +++ b/cairo/tests/legacy/utils/test_bytes_legacy.py @@ -1,5 +1,5 @@ import pytest -from hypothesis import given +from hypothesis import Verbosity, given, settings from hypothesis.strategies import binary, integers from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME @@ -39,6 +39,7 @@ def test_should_raise_when_value_sup_31_bytes(self, cairo_run, n): # This test checks the function fails if the % base is removed from the hint # All values up to 256 will have the same decomposition if the it is removed @given(n=integers(min_value=256, max_value=2**248 - 1)) + @settings(verbosity=Verbosity.quiet) def test_should_raise_when_byte_value_not_modulo_base( self, cairo_programs, cairo_run, n ): @@ -63,6 +64,7 @@ def test_should_raise_when_byte_value_not_modulo_base( != 0 ) ) + @settings(verbosity=Verbosity.quiet) def test_should_raise_when_bytes_len_is_not_minimal( self, cairo_programs, cairo_run, n ): diff --git a/cairo/tests/utils/args_gen.py b/cairo/tests/utils/args_gen.py index 04194737a..f1d68d6b2 100644 --- a/cairo/tests/utils/args_gen.py +++ b/cairo/tests/utils/args_gen.py @@ -1182,6 +1182,10 @@ def default_factory(): ] ) + all_preimages = { + poseidon_hash_many(k) if len(k) != 1 else k[0]: k for k in data.keys() + } + segments.load_data(dict_ptr, initial_data) current_ptr = dict_ptr + len(initial_data) @@ -1189,10 +1193,15 @@ def default_factory(): dict_manager.trackers[dict_ptr.segment_index] = DictTracker( data=data, current_ptr=current_ptr ) + # Set a new field in the dict_manager to store all preimages. + if not hasattr(dict_manager, "preimages"): + dict_manager.preimages = {} + dict_manager.preimages.update(all_preimages) else: default_value = ( data.default_factory() if isinstance(data, defaultdict) else None ) + dict_manager.preimages.update(all_preimages) dict_manager.trackers[dict_ptr.segment_index] = RustDictTracker( data=data, current_ptr=current_ptr, diff --git a/crates/cairo-addons/src/vm/dict_manager.rs b/crates/cairo-addons/src/vm/dict_manager.rs index 9fe48425b..d3ed0d33e 100644 --- a/crates/cairo-addons/src/vm/dict_manager.rs +++ b/crates/cairo-addons/src/vm/dict_manager.rs @@ -4,12 +4,15 @@ use cairo_vm::{ }, types::relocatable::MaybeRelocatable, }; -use pyo3::{prelude::*, types::PyTuple}; +use pyo3::{ + prelude::*, + types::{PyDict, PyTuple}, +}; use std::{cell::RefCell, collections::HashMap, rc::Rc}; use super::{maybe_relocatable::PyMaybeRelocatable, relocatable::PyRelocatable}; -#[derive(FromPyObject, Eq, PartialEq, Hash)] +#[derive(FromPyObject, Eq, PartialEq, Hash, Debug)] pub enum PyDictKey { #[pyo3(transparent)] Simple(PyMaybeRelocatable), @@ -82,6 +85,51 @@ impl PyTrackerMapping { } } +// Object returned by DictManager.preimages enabling access to the preimages by index and mutating +/// the preimages with manager.preimages[index] = preimage +#[pyclass(name = "PreimagesMapping", unsendable)] +pub struct PyPreimagesMapping { + inner: Rc>, +} + +#[pymethods] +impl PyPreimagesMapping { + fn __getitem__(&self, key: PyMaybeRelocatable) -> PyResult { + Ok(self + .inner + .borrow() + .preimages + .get(&key.clone().into()) + .cloned() + .ok_or_else(|| { + PyErr::new::(format!("key {:?} not found", key)) + })? + .into()) + } + + fn __setitem__(&mut self, key: PyMaybeRelocatable, value: PyDictKey) -> PyResult<()> { + self.inner.borrow_mut().preimages.insert(key.into(), value.into()); + Ok(()) + } + + fn update(&mut self, other: Bound<'_, PyDict>) -> PyResult<()> { + let other_dict = other.extract::>()?; + self.inner + .borrow_mut() + .preimages + .extend(other_dict.into_iter().map(|(k, v)| (k.into(), v.into()))); + Ok(()) + } + + fn __repr__(&self) -> PyResult { + let inner = self.inner.borrow(); + let mut pairs: Vec<_> = inner.preimages.iter().collect(); + pairs.sort_by(|(k1, _), (k2, _)| k1.partial_cmp(k2).unwrap_or(std::cmp::Ordering::Equal)); + let data_str = + pairs.into_iter().map(|(k, v)| format!("{}: {}", k, v)).collect::>().join(", "); + Ok(format!("PreimagesMapping({{{}}})", data_str)) + } +} #[pyclass(name = "DictManager", unsendable)] pub struct PyDictManager { pub inner: Rc>, @@ -99,6 +147,19 @@ impl PyDictManager { Ok(PyTrackerMapping { inner: self.inner.clone() }) } + #[getter] + fn get_preimages(&self) -> PyResult { + Ok(PyPreimagesMapping { inner: self.inner.clone() }) + } + + #[setter] + fn set_preimages(&mut self, value: Bound<'_, PyDict>) -> PyResult<()> { + let preimages = value.extract::>()?; + self.inner.borrow_mut().preimages = + preimages.into_iter().map(|(k, v)| (k.into(), v.into())).collect(); + Ok(()) + } + fn get_tracker(&self, ptr: PyRelocatable) -> PyResult { self.inner .borrow() diff --git a/crates/cairo-addons/src/vm/felt.rs b/crates/cairo-addons/src/vm/felt.rs index 1e2e00216..4372e71ef 100644 --- a/crates/cairo-addons/src/vm/felt.rs +++ b/crates/cairo-addons/src/vm/felt.rs @@ -83,3 +83,9 @@ impl From for PyFelt { Self { inner: felt } } } + +impl From for Felt252 { + fn from(felt: PyFelt) -> Self { + felt.inner + } +} diff --git a/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs b/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs index ae60662b5..f9bcb8d3b 100644 --- a/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs +++ b/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs @@ -49,8 +49,8 @@ pub fn hashdict_read() -> Hint { // Get dictionary pointer and setup tracker let dict_ptr = get_ptr_from_var_name("dict_ptr", vm, ids_data, ap_tracking)?; let dict_manager_ref = exec_scopes.get_dict_manager()?; - let mut dict = dict_manager_ref.borrow_mut(); - let tracker = dict.get_tracker_mut(dict_ptr)?; + let mut dict_manager = dict_manager_ref.borrow_mut(); + let tracker = dict_manager.get_tracker_mut(dict_ptr)?; tracker.current_ptr.offset += DICT_ACCESS_SIZE; let key = get_ptr_from_var_name("key", vm, ids_data, ap_tracking)?; @@ -65,7 +65,11 @@ pub fn hashdict_read() -> Hint { tracker.get_value(&dict_key).and_then(|value| { insert_value_from_var_name("value", value.clone(), vm, ids_data, ap_tracking) - }) + })?; + + let hashed_key = compute_hash_key(&dict_key, key_len); + dict_manager.preimages.insert(hashed_key.into(), dict_key); + Ok(()) }, ) } @@ -82,8 +86,8 @@ pub fn hashdict_write() -> Hint { // Get dictionary pointer and setup tracker let dict_ptr = get_ptr_from_var_name("dict_ptr", vm, ids_data, ap_tracking)?; let dict_manager_ref = exec_scopes.get_dict_manager()?; - let mut dict = dict_manager_ref.borrow_mut(); - let tracker = dict.get_tracker_mut(dict_ptr)?; + let mut dict_manager = dict_manager_ref.borrow_mut(); + let tracker = dict_manager.get_tracker_mut(dict_ptr)?; tracker.current_ptr.offset += DICT_ACCESS_SIZE; let key = get_ptr_from_var_name("key", vm, ids_data, ap_tracking)?; @@ -107,6 +111,8 @@ pub fn hashdict_write() -> Hint { })?; tracker.insert_value(&dict_key, &new_value); + let hashed_key = compute_hash_key(&dict_key, key_len); + dict_manager.preimages.insert(hashed_key.into(), dict_key); Ok(()) }, ) @@ -217,14 +223,16 @@ pub fn hashdict_read_from_key() -> Hint { // Get dictionary tracker let dict_ptr = get_ptr_from_var_name("dict_ptr_stop", vm, ids_data, ap_tracking)?; let dict_manager_ref = exec_scopes.get_dict_manager()?; - let mut dict = dict_manager_ref.borrow_mut(); - let tracker = dict.get_tracker_mut(dict_ptr)?; + let mut dict_manager = dict_manager_ref.borrow_mut(); + let preimages = &dict_manager.preimages.clone(); + let tracker = dict_manager.get_tracker_mut(dict_ptr)?; // Find matching preimage and get its value. This hint can also be called on non-hashed // keys. let simple_key = DictKey::Simple(hashed_key.into()); - let preimage = - _get_preimage_for_hashed_key(hashed_key, tracker).unwrap_or(&simple_key).clone(); + let preimage = _get_preimage_for_hashed_key(hashed_key.into(), preimages) + .unwrap_or(&simple_key) + .clone(); let value = tracker .get_value(&preimage) .map_err(|_| { @@ -253,13 +261,12 @@ pub fn get_preimage_for_key() -> Hint { let hashed_key = get_integer_from_var_name("key", vm, ids_data, ap_tracking)?; // Get dictionary tracker - let dict_ptr = get_ptr_from_var_name("dict_ptr_stop", vm, ids_data, ap_tracking)?; let dict_manager_ref = exec_scopes.get_dict_manager()?; - let dict = dict_manager_ref.borrow(); - let tracker = dict.get_tracker(dict_ptr)?; + let dict_manager = dict_manager_ref.borrow(); + let preimages = &dict_manager.preimages; // Find matching preimage - let preimage = _get_preimage_for_hashed_key(hashed_key, tracker)?; + let preimage = _get_preimage_for_hashed_key(hashed_key.into(), preimages)?; // Write preimage data to memory let preimage_data_ptr = @@ -297,13 +304,14 @@ pub fn copy_hashdict_tracker_entry() -> Hint { get_ptr_from_var_name("source_ptr_stop", vm, ids_data, ap_tracking)?; let dest_ptr = get_ptr_from_var_name("dest_ptr", vm, ids_data, ap_tracking)?; let dict_manager_ref = exec_scopes.get_dict_manager()?; - let mut dict = dict_manager_ref.borrow_mut(); + let mut dict_manager = dict_manager_ref.borrow_mut(); + let preimages = &dict_manager.preimages.clone(); - let source_tracker = dict.get_tracker_mut(source_ptr_stop)?; + let source_tracker = dict_manager.get_tracker_mut(source_ptr_stop)?; // Find matching preimage from source tracker data let key_hash = get_integer_from_var_name("source_key", vm, ids_data, ap_tracking)?; - let preimage = _get_preimage_for_hashed_key(key_hash, source_tracker)?.clone(); + let preimage = _get_preimage_for_hashed_key(key_hash.into(), preimages)?.clone(); let value = source_tracker .get_value(&preimage) .map_err(|_| { @@ -314,7 +322,7 @@ pub fn copy_hashdict_tracker_entry() -> Hint { .clone(); // Update destination tracker - let dest_tracker = dict.get_tracker_mut(dest_ptr)?; + let dest_tracker = dict_manager.get_tracker_mut(dest_ptr)?; dest_tracker.current_ptr.offset += DICT_ACCESS_SIZE; dest_tracker.insert_value(&preimage, &value.clone()); @@ -335,18 +343,24 @@ pub fn track_precompiles() -> Hint { // Get dictionary pointer and setup tracker let dict_ptr = get_ptr_from_var_name("dict_ptr", vm, ids_data, ap_tracking)?; let dict_manager_ref = exec_scopes.get_dict_manager()?; - let mut dict = dict_manager_ref.borrow_mut(); - let tracker = dict.get_tracker_mut(dict_ptr)?; + let mut dict_manager = dict_manager_ref.borrow_mut(); + let tracker = dict_manager.get_tracker_mut(dict_ptr)?; let precompiles = Precompiles::cancun().addresses().collect::>(); - for address in &precompiles { - let preimage = - vec![MaybeRelocatable::Int(Felt252::from_bytes_le_slice(&address.0 .0))]; - tracker - .insert_value(&DictKey::Compound(preimage), &MaybeRelocatable::Int(1.into())); + tracker.current_ptr.offset += precompiles.len() * DICT_ACCESS_SIZE; + + let mut preimage_entries = Vec::new(); + for precompile_address in &precompiles { + let address_felt = Felt252::from_bytes_le_slice(&precompile_address.0 .0); + let preimage = vec![MaybeRelocatable::Int(address_felt)]; + let dict_key = DictKey::Compound(preimage); + tracker.insert_value(&dict_key, &MaybeRelocatable::Int(1.into())); + preimage_entries.push((address_felt, dict_key)); } - tracker.current_ptr.offset += precompiles.len() * DICT_ACCESS_SIZE; + for (address_felt, dict_key) in preimage_entries { + dict_manager.preimages.insert(address_felt.into(), dict_key); + } Ok(()) }, @@ -371,24 +385,28 @@ fn build_compound_key( /// Helper function to find a preimage in a tracker's dictionary given a hashed key fn _get_preimage_for_hashed_key( - hashed_key: Felt252, - tracker: &DictTracker, + hashed_key: MaybeRelocatable, + preimages: &HashMap, ) -> Result<&DictKey, HintError> { - tracker - .get_dictionary_ref() - .keys() - .find(|key| match key { + preimages.get(&hashed_key).ok_or_else(|| { + HintError::CustomHint(format!("No preimage found for hashed key {}", hashed_key).into()) + }) +} + +/// Helper function to compute the hash key from a DictKey +fn compute_hash_key(dict_key: &DictKey, key_len: usize) -> Felt252 { + if key_len != 1 { + match dict_key { DictKey::Compound(values) => { - let felt_values: Vec = values.iter().filter_map(|v| v.get_int()).collect(); - if felt_values.len() == 1 { - felt_values[0] == hashed_key - } else { - poseidon_hash_many(felt_values.iter()) == hashed_key - } + let ints: Vec = values.iter().map(|v| v.get_int().unwrap()).collect(); + poseidon_hash_many(&ints) } - _ => false, - }) - .ok_or_else(|| { - HintError::CustomHint(format!("No preimage found for hashed key {}", hashed_key).into()) - }) + DictKey::Simple(_) => panic!("Unreachable"), + } + } else { + match dict_key { + DictKey::Compound(values) => values[0].get_int().unwrap(), + DictKey::Simple(value) => value.get_int().unwrap(), + } + } } diff --git a/crates/cairo-addons/src/vm/maybe_relocatable.rs b/crates/cairo-addons/src/vm/maybe_relocatable.rs index 92d903756..034cf6658 100644 --- a/crates/cairo-addons/src/vm/maybe_relocatable.rs +++ b/crates/cairo-addons/src/vm/maybe_relocatable.rs @@ -3,7 +3,7 @@ use cairo_vm::types::relocatable::MaybeRelocatable as RustMaybeRelocatable; use num_bigint::BigUint; use pyo3::{FromPyObject, IntoPy, PyObject, Python}; -#[derive(FromPyObject, Eq, PartialEq, Hash, Debug)] +#[derive(FromPyObject, Eq, PartialEq, Hash, Debug, Clone)] pub enum PyMaybeRelocatable { #[pyo3(transparent)] Felt(PyFelt), diff --git a/python/cairo-addons/src/cairo_addons/hints/dict.py b/python/cairo-addons/src/cairo_addons/hints/dict.py index 5831a5280..cc931b7a5 100644 --- a/python/cairo-addons/src/cairo_addons/hints/dict.py +++ b/python/cairo-addons/src/cairo_addons/hints/dict.py @@ -68,13 +68,13 @@ def copy_dict_segment( # Same as new_dict but supports a default value base = segments.add() assert base.segment_index not in dict_manager.trackers + copied_data = { + key: segments.gen_arg(value) for key, value in current_tracker.data.items() + } dict_manager.trackers[base.segment_index] = DictTracker( data=defaultdict( current_tracker.data.default_factory, - { - key: segments.gen_arg(value) - for key, value in current_tracker.data.items() - }, + copied_data, ), current_ptr=base, ) diff --git a/python/cairo-addons/src/cairo_addons/hints/hashdict.py b/python/cairo-addons/src/cairo_addons/hints/hashdict.py index 107df5928..c934d6e1c 100644 --- a/python/cairo-addons/src/cairo_addons/hints/hashdict.py +++ b/python/cairo-addons/src/cairo_addons/hints/hashdict.py @@ -1,4 +1,4 @@ -from starkware.cairo.common.dict import DictManager, DictTracker +from starkware.cairo.common.dict import DictManager from starkware.cairo.lang.vm.memory_dict import MemoryDict from starkware.cairo.lang.vm.memory_segments import MemorySegmentManager from starkware.cairo.lang.vm.vm_consts import VmConsts @@ -8,6 +8,8 @@ @register_hint def hashdict_read(dict_manager: DictManager, ids: VmConsts, memory: MemoryDict): + from starkware.cairo.lang.vm.crypto import poseidon_hash_many + dict_tracker = dict_manager.get_tracker(ids.dict_ptr) dict_tracker.current_ptr += ids.DictAccess.SIZE preimage = tuple([memory[ids.key + i] for i in range(ids.key_len)]) @@ -18,6 +20,9 @@ def hashdict_read(dict_manager: DictManager, ids: VmConsts, memory: MemoryDict): else: ids.value = dict_tracker.data.default_factory() + hashed_key = poseidon_hash_many(preimage) if len(preimage) != 1 else preimage[0] + dict_manager.preimages[hashed_key] = preimage + @register_hint def hashdict_read_from_key( @@ -28,7 +33,7 @@ def hashdict_read_from_key( dict_tracker = dict_manager.get_tracker(ids.dict_ptr_stop) try: - preimage = _get_preimage_for_hashed_key(ids.key, dict_tracker) or ids.key + preimage = _get_preimage_for_hashed_key(ids.key, dict_manager) or ids.key except Exception: ids.value = dict_tracker.data.default_factory() else: @@ -37,6 +42,8 @@ def hashdict_read_from_key( @register_hint def hashdict_write(dict_manager: DictManager, ids: VmConsts, memory: MemoryDict): + from starkware.cairo.lang.vm.crypto import poseidon_hash_many + dict_tracker = dict_manager.get_tracker(ids.dict_ptr) dict_tracker.current_ptr += ids.DictAccess.SIZE preimage = tuple([memory[ids.key + i] for i in range(ids.key_len)]) @@ -47,6 +54,9 @@ def hashdict_write(dict_manager: DictManager, ids: VmConsts, memory: MemoryDict) ids.dict_ptr.prev_value = dict_tracker.data.default_factory() dict_tracker.data[preimage] = ids.new_value + hashed_key = poseidon_hash_many(preimage) if len(preimage) != 1 else preimage[0] + dict_manager.preimages[hashed_key] = preimage + @register_hint def get_keys_for_address_prefix( @@ -77,11 +87,7 @@ def get_preimage_for_key( ): from cairo_addons.hints.hashdict import _get_preimage_for_hashed_key - preimage = list( - _get_preimage_for_hashed_key( - ids.key, dict_manager.get_tracker(ids.dict_ptr_stop) - ) - ) + preimage = list(_get_preimage_for_hashed_key(ids.key, dict_manager)) segments.write_arg(ids.preimage_data, preimage) ids.preimage_len = len(preimage) @@ -89,7 +95,7 @@ def get_preimage_for_key( @register_hint def copy_hashdict_tracker_entry(dict_manager: DictManager, ids: VmConsts): obj_tracker = dict_manager.get_tracker(ids.dict_ptr_stop.address_) - preimage = _get_preimage_for_hashed_key(ids.dict_ptr.key.value, obj_tracker) + preimage = _get_preimage_for_hashed_key(ids.dict_ptr.key.value, dict_manager) dict_tracker = dict_manager.get_tracker(ids.branch_ptr.address_) dict_tracker.current_ptr += ids.DictAccess.SIZE dict_tracker.data[preimage] = obj_tracker.data[preimage] @@ -97,20 +103,11 @@ def copy_hashdict_tracker_entry(dict_manager: DictManager, ids: VmConsts): def _get_preimage_for_hashed_key( hashed_key: int, - dict_tracker: DictTracker, + dict_manager: DictManager, ) -> tuple: - from starkware.cairo.lang.vm.crypto import poseidon_hash_many - - # Get the key in the dict that matches the hashed value - preimage = next( - key - for key in dict_tracker.data.keys() - if ( - key[0] == hashed_key - if len(key) == 1 - else poseidon_hash_many(key) == hashed_key - ) - ) + if hashed_key not in dict_manager.preimages: + raise Exception("No preimage found for hashed key") + preimage = dict_manager.preimages[hashed_key] return preimage @@ -125,5 +122,6 @@ def track_precompiles( for key in PRE_COMPILED_CONTRACTS.keys(): preimage = (int.from_bytes(key, "little"),) dict_tracker.data[preimage] = 1 + dict_manager.preimages[preimage[0]] = preimage dict_tracker.current_ptr += len(PRE_COMPILED_CONTRACTS) * ids.DictAccess.SIZE diff --git a/python/cairo-addons/src/cairo_addons/testing/fixtures.py b/python/cairo-addons/src/cairo_addons/testing/fixtures.py index 8946a8785..2182d978b 100644 --- a/python/cairo-addons/src/cairo_addons/testing/fixtures.py +++ b/python/cairo-addons/src/cairo_addons/testing/fixtures.py @@ -178,7 +178,7 @@ def cairo_run_py( cairo_files, main_paths, request, - coverage, + coverage=coverage, ) diff --git a/python/cairo-core/tests/src/cairo_core/test_maths.py b/python/cairo-core/tests/src/cairo_core/test_maths.py index c0b18c228..1f83e7ef2 100644 --- a/python/cairo-core/tests/src/cairo_core/test_maths.py +++ b/python/cairo-core/tests/src/cairo_core/test_maths.py @@ -1,5 +1,5 @@ import pytest -from hypothesis import assume, given, settings +from hypothesis import Verbosity, assume, given, settings from hypothesis import strategies as st from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME @@ -81,6 +81,7 @@ def test_felt252_to_bytes_le_should_panic_on_len_too_big( value=st.integers(min_value=1, max_value=2**248 - 1), len_=st.integers(min_value=1, max_value=31), ) + @settings(verbosity=Verbosity.quiet) def test_felt252_to_bytes_le_should_panic_on_wrong_output( self, cairo_programs, cairo_run, value, len_ ): @@ -148,6 +149,7 @@ def test_felt252_to_bytes_be_should_panic_on_len_too_big( value=st.integers(min_value=1, max_value=2**248 - 1), len_=st.integers(min_value=1, max_value=31), ) + @settings(verbosity=Verbosity.quiet) def test_felt252_to_bytes_be_should_panic_on_wrong_output( self, cairo_programs, cairo_run, value, len_ ): diff --git a/python/cairo-ec/tests/circuits/test_circuits.py b/python/cairo-ec/tests/circuits/test_circuits.py index 3175b740a..c35c3e995 100644 --- a/python/cairo-ec/tests/circuits/test_circuits.py +++ b/python/cairo-ec/tests/circuits/test_circuits.py @@ -2,7 +2,7 @@ import pytest from ethereum.crypto.finite_field import PrimeField -from hypothesis import assume, given +from hypothesis import Verbosity, assume, given, settings from hypothesis import strategies as st from sympy import sqrt_mod from sympy.core.numbers import mod_inverse @@ -49,6 +49,7 @@ class Curve(ECBase): class TestCircuits: class TestModOps: @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_add(self, cairo_program, cairo_run, prime_cls, st_prime, data): inputs = {"x": data.draw(st_prime), "y": data.draw(st_prime)} values_ptr = [limb for v in inputs.values() for limb in int_to_uint384(v)] @@ -84,6 +85,7 @@ def test_add(self, cairo_program, cairo_run, prime_cls, st_prime, data): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_sub(self, cairo_program, cairo_run, prime_cls, st_prime, data): inputs = {"x": data.draw(st_prime), "y": data.draw(st_prime)} values_ptr = [limb for v in inputs.values() for limb in int_to_uint384(v)] @@ -119,6 +121,7 @@ def test_sub(self, cairo_program, cairo_run, prime_cls, st_prime, data): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_mul(self, cairo_program, cairo_run, prime_cls, st_prime, data): inputs = {"x": data.draw(st_prime), "y": data.draw(st_prime)} values_ptr = [limb for v in inputs.values() for limb in int_to_uint384(v)] @@ -154,6 +157,7 @@ def test_mul(self, cairo_program, cairo_run, prime_cls, st_prime, data): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_div(self, cairo_program, cairo_run, prime, data, prime_cls): inputs = { "x": data.draw(st.integers(min_value=0, max_value=prime - 1)), @@ -194,6 +198,7 @@ def test_div(self, cairo_program, cairo_run, prime, data, prime_cls): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_diff_ratio(self, cairo_program, cairo_run, prime_cls, st_prime, data): inputs = {"x": data.draw(st_prime), "y": data.draw(st_prime)} assume(inputs["x"] != inputs["y"]) @@ -233,6 +238,7 @@ def test_diff_ratio(self, cairo_program, cairo_run, prime_cls, st_prime, data): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_sum_ratio(self, cairo_program, cairo_run, prime_cls, st_prime, data): inputs = {"x": data.draw(st_prime), "y": data.draw(st_prime)} assume(inputs["x"] != -inputs["y"]) @@ -272,6 +278,7 @@ def test_sum_ratio(self, cairo_program, cairo_run, prime_cls, st_prime, data): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_inv(self, cairo_program, cairo_run, prime, data, prime_cls): inputs = { "x": data.draw(st.integers(min_value=1, max_value=prime - 1)), @@ -312,6 +319,7 @@ def test_inv(self, cairo_program, cairo_run, prime, data, prime_cls): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_assert_is_quad_residue( self, cairo_program, cairo_run, curve, data, st_prime ): @@ -346,6 +354,7 @@ def test_assert_is_quad_residue( class TestEcOps: @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_ec_add(self, cairo_program, cairo_run, curve, data, st_prime): seed_p = data.draw(st_prime) seed_q = data.draw(st_prime) @@ -388,6 +397,7 @@ def test_ec_add(self, cairo_program, cairo_run, curve, data, st_prime): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_ec_double(self, cairo_program, cairo_run, curve, data, st_prime): seed_p = data.draw(st_prime) p = curve.random_point(x=seed_p) @@ -427,6 +437,7 @@ def test_ec_double(self, cairo_program, cairo_run, curve, data, st_prime): ) @given(data=st.data()) + @settings(verbosity=Verbosity.quiet) def test_assert_is_on_curve( self, cairo_program, cairo_run, curve, data, st_prime ):