Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Move missing cairo-1 hints from starknet_in_rust repo #1143

Merged
merged 103 commits into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
ad090c0
Implement TryFrom<CasmContractClass> for Program
fmoletta Apr 28, 2023
814f62f
Add cairo1hintprocessor dependency
fmoletta Apr 28, 2023
5ad52b3
Map hints to pc
fmoletta May 2, 2023
2c80935
Add Cairo1HintProcessor
fmoletta May 2, 2023
31833c0
Move cairo-1-hint-processor to cairo-rs crate
fmoletta May 2, 2023
a0974fc
fixes
fmoletta May 2, 2023
3257b9d
Fix test helper
fmoletta May 2, 2023
6eb32a6
Remove allow
fmoletta May 2, 2023
95be386
fix test func
fmoletta May 3, 2023
0ce7380
Add builtins to test
fmoletta May 3, 2023
ee4db2c
Extract builtins from contract_class
fmoletta May 3, 2023
f0d4151
Add _builtin to builtin names in etrypoint data
fmoletta May 3, 2023
4032a94
Copy logic from cairo1 contract execution in starknet
fmoletta May 4, 2023
6c9be63
Remove unused code
fmoletta May 4, 2023
52984d7
Use lower initial_gas value
fmoletta May 4, 2023
151375f
Add program segment size argument
fmoletta May 4, 2023
f11e350
Check return values in run_cairo_1_entrypoint fn
fmoletta May 4, 2023
f466aa7
Remove debug prints
fmoletta May 4, 2023
8a528a0
Add basic fibonacci test
fmoletta May 4, 2023
c4fbe31
Add another fibonacci case
fmoletta May 4, 2023
5debb70
Always verify secure
fmoletta May 4, 2023
4d614a8
Clippy
fmoletta May 4, 2023
df1bf8f
Compile casm contracts when running test target
fmoletta May 4, 2023
59b6381
Remove unwrap from cell_ref_to_relocatable
fmoletta May 4, 2023
2649829
Remove paniking macro from extract_buffer
fmoletta May 4, 2023
ecb58d6
Misc improvements
fmoletta May 4, 2023
2d9362d
Misc improvements
fmoletta May 4, 2023
38be92c
Misc improvements
fmoletta May 4, 2023
a82308b
Misc improvements
fmoletta May 4, 2023
8d6c5cb
Remove unwraps & asserts from DictSquashExecScope::pop_current_key
fmoletta May 4, 2023
4e7f2e0
Remove unwraps & asserts from DictManagerExecScope::new_default_dict
fmoletta May 4, 2023
75218c8
Remove expect from get_dict_tracker
fmoletta May 4, 2023
b06f563
Add constants for cairo 1 compiler binaries in makefile
fmoletta May 4, 2023
7d543ae
Add cairo 1 compiler to deps target in makefile
fmoletta May 4, 2023
47ea449
Add cairo folder to clean target
fmoletta May 4, 2023
6156c0f
Remove todo from execute method
fmoletta May 4, 2023
a0e28f5
Separate helper functions from Cairo1HintProcessor implementation
fmoletta May 4, 2023
78e3c8a
Add untracked file
fmoletta May 4, 2023
6a96be2
Fix
fmoletta May 4, 2023
4423074
Merge branch 'main' of github.com:lambdaclass/cairo-rs into run-casm-…
fmoletta May 4, 2023
b902488
Add changelog entry
fmoletta May 4, 2023
2b40d20
Add a job to compile cairo 1 contracts in ci
fmoletta May 4, 2023
04e966a
Add job dependency
fmoletta May 4, 2023
e13bb43
Fix yml syntax
fmoletta May 4, 2023
0cb9790
Fix yml syntax
fmoletta May 4, 2023
1461d56
Temporarily extempt cairo-1-hint-processor from codecov
fmoletta May 4, 2023
77d370e
Fix yml syntax
fmoletta May 4, 2023
44d87e1
Fix workflow
fmoletta May 4, 2023
2e0701b
Remove cache code from new job
fmoletta May 4, 2023
85791c5
Fix yml syntax
fmoletta May 4, 2023
736b973
Fix wrong path
fmoletta May 4, 2023
88f2cad
Fix makefile
fmoletta May 4, 2023
af264a5
Build only compiler binaries
fmoletta May 4, 2023
367515f
Add cairo-1-contracts-cache
fmoletta May 4, 2023
e3635a4
Fetch contracts cache in jobs that need them
fmoletta May 4, 2023
04be04a
Use no-std version of HashMap
fmoletta May 4, 2023
b944e9a
Import stdlib::prelude::*
fmoletta May 4, 2023
8f78351
Wrap print in not-wasm block
fmoletta May 4, 2023
806ee39
Remove std path
fmoletta May 5, 2023
7195ffe
use slices instead of vec
fmoletta May 5, 2023
6c8c334
Make DictSquashExecScope fields private
fmoletta May 5, 2023
917c9cb
Import hint processor dependencies without default features
fmoletta May 5, 2023
a47b09c
-Clippy
fmoletta May 5, 2023
b9417c5
Add type
fmoletta May 5, 2023
f96c5df
Compile cairo 1 contracts in build-programs job
fmoletta May 5, 2023
ddeefa1
Rename cache
fmoletta May 5, 2023
a6b0913
Use target dependency instead of explicit $(MAKE)
fmoletta May 5, 2023
329e17f
Fix yml syntax
fmoletta May 5, 2023
2cd1d44
Check for cairo folder before cloning cairo repo
fmoletta May 5, 2023
bcdfa80
Ommit folder name
fmoletta May 5, 2023
28bfe83
Swap paths
fmoletta May 5, 2023
a101e62
Merge branch 'main' into run-casm-contract-class
fmoletta May 5, 2023
dd05e21
Add cairo-1-hints feature flag
fmoletta May 5, 2023
c2e3e49
Merge branch 'run-casm-contract-class' of github.com:lambdaclass/cair…
fmoletta May 5, 2023
e91ca98
Add compile-hint feature to tests run in workflow
fmoletta May 5, 2023
36a2957
Add cairo-1-hints to test_utils
fmoletta May 5, 2023
76534a9
Add cairo-1-hints to test_utils
fmoletta May 5, 2023
009b348
Use both paths when fetching compiled test data
fmoletta May 5, 2023
0585919
Remove cairo-1-hints feature from test_utils feature
fmoletta May 5, 2023
02bf013
Move dependencies to cairo-1-hints feature
fmoletta May 5, 2023
8714bfb
Merge branch 'main' into run-casm-contract-class
fmoletta May 8, 2023
f0dcbb6
Update CHANGELOG.md
fmoletta May 8, 2023
aa40e20
Move Felt252DictEntryInit hint impl
fmoletta May 8, 2023
4f3aac8
Add hint Felt252DictEntryUpdate
fmoletta May 8, 2023
de01812
Add hint GetCurrentAccessDelta
fmoletta May 8, 2023
34e1c21
Add hint InitSquashData
fmoletta May 8, 2023
b1419e1
Add hint AllocConstantSize
fmoletta May 8, 2023
e7ef58d
Add hint GetCurrentAccessIndex
fmoletta May 8, 2023
b111a13
Add hint Uint256SquareRoot
fmoletta May 8, 2023
f4f97e9
Fix cfg directive
fmoletta May 8, 2023
513bca1
Merge branch 'run-casm-contract-class' of github.com:lambdaclass/cair…
fmoletta May 8, 2023
4464173
Merge branch 'run-casm-contract-class' into add-cairo-1-hints
fmoletta May 8, 2023
a56eb04
Misc fixes
fmoletta May 8, 2023
10ae5bf
Add changelog entry
fmoletta May 8, 2023
d7fc2e7
Add hint ShouldContinueSquashLoop
fmoletta May 8, 2023
08fca47
Add hint FieldSqrt
fmoletta May 8, 2023
b03d9a1
Fixes
fmoletta May 8, 2023
8de5453
Add cairo-1-hints to test workflow
fmoletta May 8, 2023
d1c9dda
Add Cairo 1 considerations for Gitignore and Makefile (#1144)
rcatalan98 May 8, 2023
c195341
Merge branch 'run-casm-contract-class' into add-cairo-1-hints
fmoletta May 8, 2023
92b6af5
Merge branch 'main' into add-cairo-1-hints
fmoletta May 8, 2023
384d92f
Merge branch 'main' into add-cairo-1-hints
fmoletta May 9, 2023
85a11b7
Update CHANGELOG.md
fmoletta May 9, 2023
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

#### Upcoming Changes

* Add more hints to `Cairo1HintProcessor` [#1143](https://github.com/lambdaclass/cairo-rs/pull/1098)

* `Cairo1HintProcessor` can now run the following hints:
* Felt252DictEntryInit
* Felt252DictEntryUpdate
* GetCurrentAccessDelta
* InitSquashData
* AllocConstantSize
* GetCurrentAccessIndex
* ShouldContinueSquashLoop
* FieldSqrt

* Add a test for the `DivMod` hint [#1138](https://github.com/lambdaclass/cairo-rs/pull/1138).

* Add some small considerations regarding Cairo 1 programs [#1144](https://github.com/lambdaclass/cairo-rs/pull/1144):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub struct DictSquashExecScope {
/// A map from key to the list of indices accessing it, each list in reverse order.
pub(crate) access_indices: HashMap<Felt252, Vec<Felt252>>,
/// Descending list of keys.
keys: Vec<Felt252>,
pub(crate) keys: Vec<Felt252>,
}

impl DictSquashExecScope {
Expand Down
264 changes: 264 additions & 0 deletions src/hint_processor/cairo_1_hint_processor/hint_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::any_box;
use crate::felt::{felt_str, Felt252};
use crate::hint_processor::cairo_1_hint_processor::dict_manager::DictSquashExecScope;
use crate::hint_processor::hint_processor_definition::HintReference;
use crate::types::relocatable::Relocatable;

use crate::stdlib::collections::HashMap;
use crate::stdlib::prelude::*;
Expand All @@ -26,6 +27,12 @@ use num_bigint::BigUint;
use num_integer::Integer;
use num_traits::{cast::ToPrimitive, Zero};

/// Execution scope for constant memory allocation.
struct MemoryExecScope {
/// The first free address in the segment.
next_address: Relocatable,
}

#[derive(MontConfig)]
#[modulus = "3618502788666131213697322783095070105623107215331596699973092056135872020481"]
#[generator = "3"]
Expand Down Expand Up @@ -174,6 +181,31 @@ impl Cairo1HintProcessor {
Hint::Core(CoreHint::ShouldSkipSquashLoop { should_skip_loop }) => {
self.should_skip_squash_loop(vm, exec_scopes, should_skip_loop)
}
Hint::Core(CoreHint::Felt252DictEntryInit { dict_ptr, key }) => {
self.dict_entry_init(vm, exec_scopes, dict_ptr, key)
}
Hint::Core(CoreHint::Felt252DictEntryUpdate { dict_ptr, value }) => {
self.felt_252_dict_entry_update(vm, exec_scopes, dict_ptr, value)
}
Hint::Core(CoreHint::GetCurrentAccessDelta { index_delta_minus1 }) => {
self.get_current_access_delta(vm, exec_scopes, index_delta_minus1)
}
Hint::Core(CoreHint::InitSquashData {
dict_accesses,
n_accesses,
big_keys,
..
}) => self.init_squash_data(vm, exec_scopes, dict_accesses, n_accesses, big_keys),
Hint::Core(CoreHint::AllocConstantSize { size, dst }) => {
self.alloc_constant_size(vm, exec_scopes, size, dst)
}
Hint::Core(CoreHint::GetCurrentAccessIndex { range_check_ptr }) => {
self.get_current_access_index(vm, exec_scopes, range_check_ptr)
}
Hint::Core(CoreHint::ShouldContinueSquashLoop { should_continue }) => {
self.should_continue_squash_loop(vm, exec_scopes, should_continue)
}
Hint::Core(CoreHint::FieldSqrt { val, sqrt }) => self.field_sqrt(vm, val, sqrt),
hint => Err(HintError::UnknownHint(hint.to_string())),
}
}
Expand Down Expand Up @@ -586,6 +618,27 @@ impl Cairo1HintProcessor {
Ok(())
}

fn dict_entry_init(
&self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
dict_ptr: &ResOperand,
key: &ResOperand,
) -> Result<(), HintError> {
let (dict_base, dict_offset) = extract_buffer(dict_ptr)?;
let dict_address = get_ptr(vm, dict_base, &dict_offset)?;
let key = res_operand_get_val(vm, key)?;
let dict_manager_exec_scope =
exec_scopes.get_mut_ref::<DictManagerExecScope>("dict_manager_exec_scope")?;

let prev_value = dict_manager_exec_scope
.get_from_tracker(dict_address, &key)
.unwrap_or_else(|| DictManagerExecScope::DICT_DEFAULT_VALUE.into());

vm.insert_value((dict_address + 1)?, prev_value)
.map_err(HintError::from)
}

fn debug_print(
&self,
vm: &mut VirtualMachine,
Expand Down Expand Up @@ -660,6 +713,217 @@ impl Cairo1HintProcessor {

Ok(())
}

fn felt_252_dict_entry_update(
&self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
dict_ptr: &ResOperand,
value: &ResOperand,
) -> Result<(), HintError> {
let (dict_base, dict_offset) = extract_buffer(dict_ptr)?;
let dict_address = get_ptr(vm, dict_base, &dict_offset)?;
let key = get_double_deref_val(vm, dict_base, &(dict_offset + Felt252::from(-3)))?;
let value = res_operand_get_val(vm, value)?;
let dict_manager_exec_scope = exec_scopes
.get_mut_ref::<DictManagerExecScope>("dict_manager_exec_scope")
.map_err(|_| {
HintError::CustomHint(
"Trying to write to a dict while dict manager was not initialized.".to_string(),
)
})?;
dict_manager_exec_scope.insert_to_tracker(dict_address, key, value);

Ok(())
}

fn get_current_access_delta(
&self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
index_delta_minus1: &CellRef,
) -> Result<(), HintError> {
let dict_squash_exec_scope: &mut DictSquashExecScope =
exec_scopes.get_mut_ref("dict_squash_exec_scope")?;
let prev_access_index = dict_squash_exec_scope
.pop_current_access_index()
.ok_or(HintError::CustomHint("no accessed index".to_string()))?;
let index_delta_minus_1_val = dict_squash_exec_scope
.current_access_index()
.ok_or(HintError::CustomHint("no index accessed".to_string()))?
.clone()
- prev_access_index
- 1_u32;

vm.insert_value(
cell_ref_to_relocatable(index_delta_minus1, vm)?,
index_delta_minus_1_val,
)?;

Ok(())
}

fn init_squash_data(
&self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
dict_accesses: &ResOperand,
n_accesses: &ResOperand,
big_keys: &CellRef,
) -> Result<(), HintError> {
let dict_access_size = 3;
let rangecheck_bound = Felt252::from(u128::MAX) + 1u32;

exec_scopes.assign_or_update_variable(
"dict_squash_exec_scope",
Box::<DictSquashExecScope>::default(),
);
let dict_squash_exec_scope =
exec_scopes.get_mut_ref::<DictSquashExecScope>("dict_squash_exec_scope")?;
let (dict_accesses_base, dict_accesses_offset) = extract_buffer(dict_accesses)?;
let dict_accesses_address = get_ptr(vm, dict_accesses_base, &dict_accesses_offset)?;
let n_accesses =
res_operand_get_val(vm, n_accesses)?
.to_usize()
.ok_or(HintError::CustomHint(
"Number of accesses is too large or negative.".to_string(),
))?;

for i in 0..n_accesses {
let current_key = vm.get_integer((dict_accesses_address + i * dict_access_size)?)?;
dict_squash_exec_scope
.access_indices
.entry(current_key.into_owned())
.and_modify(|indices| indices.push(Felt252::from(i)))
.or_insert_with(|| vec![Felt252::from(i)]);
}
// Reverse the accesses in order to pop them in order later.
for (_, accesses) in dict_squash_exec_scope.access_indices.iter_mut() {
accesses.reverse();
}

dict_squash_exec_scope.keys = dict_squash_exec_scope
.access_indices
.keys()
.cloned()
.collect();
dict_squash_exec_scope.keys.sort_by(|a, b| b.cmp(a));
// big_keys indicates if the keys are greater than rangecheck_bound. If they are not
// a simple range check is used instead of assert_le_felt252.

let val = Felt252::from((dict_squash_exec_scope.keys[0] < rangecheck_bound) as u8);

vm.insert_value(cell_ref_to_relocatable(big_keys, vm)?, val)?;

vm.insert_value(
cell_ref_to_relocatable(big_keys, vm)?,
dict_squash_exec_scope
.current_key()
.ok_or(HintError::CustomHint("No current key".to_string()))?,
)?;

Ok(())
}

fn alloc_constant_size(
&self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
size: &ResOperand,
dst: &CellRef,
) -> Result<(), HintError> {
let object_size = res_operand_get_val(vm, size)?
.to_usize()
.expect("Object size too large.");
let memory_exec_scope =
match exec_scopes.get_mut_ref::<MemoryExecScope>("memory_exec_scope") {
Ok(memory_exec_scope) => memory_exec_scope,
Err(_) => {
exec_scopes.assign_or_update_variable(
"memory_exec_scope",
Box::new(MemoryExecScope {
next_address: vm.add_memory_segment(),
}),
);
exec_scopes.get_mut_ref::<MemoryExecScope>("memory_exec_scope")?
}
};

vm.insert_value(
cell_ref_to_relocatable(dst, vm)?,
memory_exec_scope.next_address,
)?;

memory_exec_scope.next_address.offset += object_size;
Ok(())
}

fn get_current_access_index(
&self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
range_check_ptr: &ResOperand,
) -> Result<(), HintError> {
let dict_squash_exec_scope: &mut DictSquashExecScope =
exec_scopes.get_mut_ref("dict_squash_exec_scope")?;
let (range_check_base, range_check_offset) = extract_buffer(range_check_ptr)?;
let range_check_ptr = get_ptr(vm, range_check_base, &range_check_offset)?;
let current_access_index =
dict_squash_exec_scope
.current_access_index()
.ok_or(HintError::CustomHint(
"No current accessed index".to_string(),
))?;
vm.insert_value(range_check_ptr, current_access_index)?;

Ok(())
}

fn should_continue_squash_loop(
&self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
dst: &CellRef,
) -> Result<(), HintError> {
let dict_squash_exec_scope: &mut DictSquashExecScope =
exec_scopes.get_mut_ref("dict_squash_exec_scope")?;
let current_access_indices = dict_squash_exec_scope
.current_access_indices()
.ok_or(HintError::EmptyCurrentAccessIndices)?;

let should_continue = Felt252::from((current_access_indices.len() > 1) as u8);

vm.insert_value(cell_ref_to_relocatable(dst, vm)?, should_continue)
.map_err(HintError::from)
}

fn field_sqrt(
&self,
vm: &mut VirtualMachine,
val: &ResOperand,
sqrt: &CellRef,
) -> Result<(), HintError> {
let value = Fq::from(res_operand_get_val(vm, val)?.to_biguint());

let three_fq = Fq::from(Felt252::new(3).to_biguint());
let res = if value.legendre().is_qr() {
value
} else {
value * three_fq
};

if let Some(root) = res.sqrt() {
let root0: BigUint = root.into_bigint().into();
let root1: BigUint = (-root).into_bigint().into();
let root = Felt252::from(std::cmp::min(root0, root1));
vm.insert_value(cell_ref_to_relocatable(sqrt, vm)?, root)
.map_err(HintError::from)
} else {
Err(HintError::CustomHint(
"Field element is not a square".to_string(),
))
}
}
}

impl HintProcessor for Cairo1HintProcessor {
Expand Down