├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cairo_programs ├── abs_value.cairo ├── assert_250_bit_element_array.cairo ├── assert_le_felt.cairo ├── assert_lt_felt.cairo ├── assert_nn.cairo ├── assert_not_equal.cairo ├── assert_not_zero.cairo ├── big_struct.cairo ├── bitwise_builtin_test.cairo ├── bitwise_output.cairo ├── bitwise_recursion.cairo ├── blake2s_felts.cairo ├── blake2s_hello_world_hash.cairo ├── blake2s_integration_tests.cairo ├── cairo_keccak.cairo ├── call_function_assign_param_by_name.cairo ├── common_signature.cairo ├── dict.cairo ├── dict_squash.cairo ├── dict_update.cairo ├── div_mod_n.cairo ├── ec_double_assign.cairo ├── ec_double_slope.cairo ├── example_blake2s.cairo ├── factorial.cairo ├── fibonacci.cairo ├── finalize_blake2s.cairo ├── finalize_blake2s_v2.cairo ├── find_element.cairo ├── function_return.cairo ├── function_return_if_print.cairo ├── function_return_to_variable.cairo ├── if_and_prime.cairo ├── if_in_function.cairo ├── if_list.cairo ├── if_reloc_equal.cairo ├── is_quad_residue.cairo ├── jmp.cairo ├── jmp_if_condition.cairo ├── keccak_add_uint256.cairo ├── keccak_builtin.cairo ├── keccak_integration_tests.cairo ├── math_cmp.cairo ├── memcpy_test.cairo ├── memory_holes.cairo ├── memset.cairo ├── multiplicative_inverse.cairo ├── not_main.cairo ├── packed_sha256.cairo ├── pedersen_and_bitwise_builtins.cairo ├── pedersen_and_bitwise_builtins_with_alloc_locals.cairo ├── pedersen_test.cairo ├── pointers.cairo ├── poseidon_builtin.cairo ├── poseidon_hash.cairo ├── pow.cairo ├── print.cairo ├── proof_programs │ ├── abs_value.cairo │ ├── assert_250_bit_element_array.cairo │ ├── assert_le_felt.cairo │ ├── assert_lt_felt.cairo │ ├── assert_nn.cairo │ ├── assert_not_equal.cairo │ ├── assert_not_zero.cairo │ ├── big_struct.cairo │ ├── bitwise_builtin_test.cairo │ ├── bitwise_output.cairo │ ├── bitwise_recursion.cairo │ ├── call_function_assign_param_by_name.cairo │ ├── common_signature.cairo │ ├── dict.cairo │ ├── dict_squash.cairo │ ├── dict_update.cairo │ ├── factorial.cairo │ ├── fibonacci.cairo │ ├── function_return.cairo │ ├── function_return_if_print.cairo │ ├── function_return_to_variable.cairo │ ├── if_and_prime.cairo │ ├── if_in_function.cairo │ ├── if_list.cairo │ ├── if_reloc_equal.cairo │ ├── is_quad_residue.cairo │ ├── jmp.cairo │ ├── jmp_if_condition.cairo │ ├── keccak_builtin.cairo │ ├── math_cmp.cairo │ ├── memcpy_test.cairo │ ├── memory_holes.cairo │ ├── memset.cairo │ ├── multiplicative_inverse.cairo │ ├── not_main.cairo │ ├── packed_sha256.cairo │ ├── pedersen_and_bitwise_builtins.cairo │ ├── pedersen_and_bitwise_builtins_with_alloc_locals.cairo │ ├── pedersen_test.cairo │ ├── pointers.cairo │ ├── poseidon_builtin.cairo │ ├── poseidon_hash.cairo │ ├── pow.cairo │ ├── print.cairo │ ├── return.cairo │ ├── reversed_register_instructions.cairo │ ├── sha256.cairo │ ├── signed_div_rem.cairo │ ├── simple_print.cairo │ ├── split_felt.cairo │ ├── split_int.cairo │ ├── sqrt.cairo │ ├── squash_dict.cairo │ ├── struct.cairo │ ├── test_addition_if.cairo │ ├── test_reverse_if.cairo │ ├── test_subtraction_if.cairo │ ├── uint384.cairo │ ├── uint384_extension.cairo │ ├── unsafe_keccak.cairo │ ├── unsafe_keccak_finalize.cairo │ ├── unsigned_div_rem.cairo │ └── usort.cairo ├── reduce.cairo ├── return.cairo ├── reversed_register_instructions.cairo ├── search_sorted_lower.cairo ├── set_add.cairo ├── sha256.cairo ├── signature.cairo ├── signed_div_rem.cairo ├── simple_print.cairo ├── split_felt.cairo ├── split_int.cairo ├── sqrt.cairo ├── squash_dict.cairo ├── struct.cairo ├── test_addition_if.cairo ├── test_reverse_if.cairo ├── test_subtraction_if.cairo ├── uint256.cairo ├── uint256_integration_tests.cairo ├── uint256_root.cairo ├── uint384.cairo ├── uint384_extension.cairo ├── unsafe_keccak.cairo ├── unsafe_keccak_finalize.cairo ├── unsigned_div_rem.cairo └── usort.cairo ├── check_fmt.sh ├── cmd └── cli │ └── main.go ├── docs ├── layout.md └── rust-integration.md ├── go.mod ├── go.sum ├── pkg ├── builtins │ ├── bitwise.go │ ├── bitwise_test.go │ ├── builtin_runner.go │ ├── builtin_runner_test.go │ ├── ec_op.go │ ├── ec_op_test.go │ ├── keccak.go │ ├── keccak_test.go │ ├── output.go │ ├── output_test.go │ ├── pedersen.go │ ├── pedersen_test.go │ ├── poseidon.go │ ├── poseidon_test.go │ ├── range_check.go │ ├── range_check_test.go │ ├── signature.go │ └── signature_test.go ├── hints │ ├── bigint_hint.go │ ├── bigint_hint_test.go │ ├── blake2s_hints.go │ ├── blake2s_hints_test.go │ ├── dict_hints.go │ ├── dict_hints_test.go │ ├── dict_manager │ │ ├── dict_manager.go │ │ └── dict_manager_test.go │ ├── ec_hint.go │ ├── ec_hint_test.go │ ├── field_utils.go │ ├── field_utils_test.go │ ├── find_element_hints.go │ ├── find_element_hints_test.go │ ├── hint_codes │ │ ├── blake2s_hint_codes.go │ │ ├── dict_hint_codes.go │ │ ├── ec_op_hints.go │ │ ├── find_element_hint_codes.go │ │ ├── keccak_hint_codes.go │ │ ├── math_cmp_hint_codes.go │ │ ├── math_hint_codes.go │ │ ├── memcpy_hint_codes.go │ │ ├── pow_hint_codes.go │ │ ├── secp_hint_codes.go │ │ ├── set_hint_codes.go │ │ ├── sha256_hint_codes.go │ │ ├── signature_hint_codes.go │ │ ├── uint256_hint_codes.go │ │ └── usort_hint_codes.go │ ├── hint_processor.go │ ├── hint_processor_test.go │ ├── hint_utils │ │ ├── bake2s_hash_test.go │ │ ├── bigint_utils.go │ │ ├── blake2s_hash.go │ │ ├── hint_reference.go │ │ ├── hint_reference_test.go │ │ ├── ids_manager.go │ │ ├── ids_manager_test.go │ │ ├── secp_utils.go │ │ ├── testing_utils.go │ │ ├── testing_utils_test.go │ │ └── uint256_utils.go │ ├── keccak_hints.go │ ├── keccak_hints_test.go │ ├── math_cmp_hints.go │ ├── math_cmp_hints_test.go │ ├── math_hints.go │ ├── math_hints_test.go │ ├── memcpy_hints.go │ ├── memcpy_hints_test.go │ ├── memset_hint_codes.go │ ├── memset_hints.go │ ├── memset_hints_test.go │ ├── pow_hints.go │ ├── pow_hints_test.go │ ├── secp_hints.go │ ├── secp_hints_test.go │ ├── set_hints.go │ ├── set_hints_test.go │ ├── sha256_hints.go │ ├── sha256_hints_test.go │ ├── signature_hints.go │ ├── signature_hints_test.go │ ├── squash_dict_hints.go │ ├── squash_dict_hints_test.go │ ├── uint256_hints.go │ ├── uint256_hints_test.go │ ├── usort_hints.go │ └── usort_hints_test.go ├── lambdaworks │ ├── lambdaworks.go │ ├── lambdaworks_test.go │ └── lib │ │ ├── .gitignore │ │ ├── lambdaworks.h │ │ └── lambdaworks │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── layouts │ ├── diluted_pool_instance_def.go │ └── layout.go ├── parser │ ├── parser.go │ └── parser_test.go ├── runners │ ├── cairo_runner.go │ ├── cairo_runner_test.go │ ├── execution_resources.go │ ├── security.go │ └── security_test.go ├── starknet_crypto │ ├── lib │ │ ├── .gitignore │ │ ├── starknet_crypto.h │ │ └── starknet_crypto │ │ │ ├── .gitignore │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── starknet_crypto.go │ └── starknet_crypto_test.go ├── types │ ├── exec_scope_test.go │ ├── exec_scope_utils.go │ └── exec_scopes.go ├── utils │ ├── math_utils.go │ ├── math_utils_test.go │ ├── utils.go │ └── utils_test.go └── vm │ ├── cairo_run │ ├── cairo_run.go │ └── cairo_run_test.go │ ├── hint_processor_interface.go │ ├── instruction.go │ ├── instruction_test.go │ ├── memory │ ├── memory.go │ ├── memory_test.go │ ├── relocatable.go │ ├── relocatable_err.go │ ├── relocatable_test.go │ ├── segments.go │ └── segments_test.go │ ├── program.go │ ├── program_test.go │ ├── run_context.go │ ├── run_resources.go │ ├── trace.go │ ├── vm_core.go │ └── vm_test.go ├── requirements.txt └── scripts ├── compare_vm_state.sh └── memory_comparator.py /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Test/Fmt 2 | 3 | on: 4 | merge_group: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | test_and_format: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Setup Go 19 | uses: actions/setup-go@v3 20 | with: 21 | go-version-file: 'go.mod' 22 | 23 | - name: Setup Rust 24 | uses: actions-rs/toolchain@v1 25 | with: 26 | toolchain: stable 27 | 28 | - name: Setup Python 29 | uses: actions/setup-python@v4 30 | with: 31 | python-version: '3.9' 32 | 33 | - name: Install cairo-lang and deps 34 | run: pip install -r requirements.txt 35 | 36 | - name: build 37 | run: make build 38 | 39 | - name: test 40 | run: make coverage 41 | 42 | - name: Upload coverage to Codecov 43 | uses: codecov/codecov-action@v3 44 | 45 | - name: format 46 | run: make check_fmt 47 | 48 | - name: Compare trace & memory with cairo-vm 49 | run: make compare_trace_memory 50 | 51 | - name: Compare trace & memory with cairo-vm in proof mode 52 | run: make compare_proof_trace_memory 53 | 54 | demos: 55 | runs-on: ubuntu-latest 56 | steps: 57 | - uses: actions/checkout@v3 58 | with: 59 | fetch-depth: 0 60 | 61 | - name: Setup Go 62 | uses: actions/setup-go@v3 63 | with: 64 | go-version-file: 'go.mod' 65 | 66 | - name: Setup Rust 67 | uses: actions-rs/toolchain@v1 68 | with: 69 | toolchain: stable 70 | 71 | - name: Setup Python 72 | uses: actions/setup-python@v4 73 | with: 74 | python-version: '3.9' 75 | 76 | - name: Install cairo-lang and deps 77 | run: pip install -r requirements.txt 78 | 79 | - name: Run fibonacci demo 80 | run: make demo_fibonacci 81 | 82 | - name: Run factorial demo 83 | run: make demo_factorial 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Ignore traces and memory outputs of the trace 15 | **.trace 16 | **.memory 17 | 18 | # Folder of the cairo-vm 19 | 20 | cairo-vm/ 21 | 22 | # Output of the go coverage tool, specifically when used with LiteIDE 23 | *.out 24 | 25 | # Dependency directories (remove the comment below to include it) 26 | # vendor/ 27 | 28 | # Go workspace file 29 | go.work 30 | 31 | # VS code configs 32 | .vscode 33 | 34 | # Compiled cairo programs 35 | *.json 36 | 37 | # python env 38 | cairo-vm-env 39 | 40 | # generated trace files 41 | cairo_programs/*.trace 42 | -------------------------------------------------------------------------------- /cairo_programs/abs_value.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math import abs_value 4 | 5 | func main{range_check_ptr: felt}() { 6 | assert abs_value(-1) = 1; 7 | assert abs_value(17) = 17; 8 | assert abs_value(-21938134) = 21938134; 9 | return (); 10 | } 11 | -------------------------------------------------------------------------------- /cairo_programs/assert_250_bit_element_array.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math import assert_250_bit 4 | from starkware.cairo.common.alloc import alloc 5 | 6 | func assert_250_bit_element_array{range_check_ptr: felt}( 7 | array: felt*, array_length: felt, iterator: felt 8 | ) { 9 | if (iterator == array_length) { 10 | return (); 11 | } 12 | assert_250_bit(array[iterator]); 13 | return assert_250_bit_element_array(array, array_length, iterator + 1); 14 | } 15 | 16 | func fill_array(array: felt*, base: felt, step: felt, array_length: felt, iterator: felt) { 17 | if (iterator == array_length) { 18 | return (); 19 | } 20 | assert array[iterator] = base + step * iterator; 21 | return fill_array(array, base, step, array_length, iterator + 1); 22 | } 23 | 24 | func main{range_check_ptr: felt}() { 25 | alloc_locals; 26 | tempvar array_length = 10; 27 | let (array: felt*) = alloc(); 28 | fill_array(array, 70000000000000000000, 300000000000000000, array_length, 0); 29 | assert_250_bit_element_array(array, array_length, 0); 30 | return (); 31 | } 32 | -------------------------------------------------------------------------------- /cairo_programs/assert_le_felt.cairo: -------------------------------------------------------------------------------- 1 | 2 | %builtins range_check 3 | from starkware.cairo.common.math import assert_le_felt 4 | 5 | func main{range_check_ptr: felt}() { 6 | assert_le_felt(1, 2); 7 | assert_le_felt(-2, -1); 8 | assert_le_felt(2, -1); 9 | return (); 10 | } 11 | -------------------------------------------------------------------------------- /cairo_programs/assert_lt_felt.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math import assert_lt 4 | from starkware.cairo.common.math import split_felt 5 | from starkware.cairo.common.math import assert_lt_felt 6 | 7 | func assert_lt_felt_manual_implementation{range_check_ptr}(a, b) { 8 | %{ 9 | from starkware.cairo.common.math_utils import assert_integer 10 | assert_integer(ids.a) 11 | assert_integer(ids.b) 12 | assert (ids.a % PRIME) < (ids.b % PRIME), \ 13 | f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.' 14 | %} 15 | alloc_locals; 16 | let (local a_high, local a_low) = split_felt(a); 17 | let (b_high, b_low) = split_felt(b); 18 | 19 | if (a_high == b_high) { 20 | assert_lt(a_low, b_low); 21 | return (); 22 | } 23 | assert_lt(a_high, b_high); 24 | return (); 25 | } 26 | 27 | func main{range_check_ptr: felt}() { 28 | let x = 5; 29 | let y = 6; 30 | 31 | tempvar m = 7; 32 | tempvar n = 7 * 7; 33 | 34 | assert_lt_felt(1, 2); 35 | assert_lt_felt(-2, -1); 36 | assert_lt_felt(1, -1); 37 | assert_lt_felt(0, 1); 38 | assert_lt_felt(x, y); 39 | assert_lt_felt(m, n); 40 | 41 | assert_lt_felt_manual_implementation(1, 2); 42 | assert_lt_felt_manual_implementation(-2, -1); 43 | assert_lt_felt_manual_implementation(1, -1); 44 | assert_lt_felt_manual_implementation(0, 1); 45 | assert_lt_felt_manual_implementation(x, y); 46 | assert_lt_felt_manual_implementation(m, n); 47 | 48 | return (); 49 | } 50 | -------------------------------------------------------------------------------- /cairo_programs/assert_nn.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math import assert_nn 4 | 5 | func main{range_check_ptr: felt}() { 6 | let x = 64; 7 | tempvar y = 64 * 64; 8 | assert_nn(1); 9 | assert_nn(x); 10 | assert_nn(y); 11 | return (); 12 | } 13 | -------------------------------------------------------------------------------- /cairo_programs/assert_not_equal.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.math import assert_not_equal 4 | 5 | func main{output_ptr: felt*}() { 6 | assert_not_equal(17, 7); 7 | assert_not_equal(cast(output_ptr, felt), cast(output_ptr + 1, felt)); 8 | assert_not_equal(-1, 1); 9 | return (); 10 | } 11 | -------------------------------------------------------------------------------- /cairo_programs/assert_not_zero.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.math import assert_not_zero 2 | 3 | func assert_not_zero_manual_implementation(value) { 4 | %{ 5 | from starkware.cairo.common.math_utils import assert_integer 6 | assert_integer(ids.value) 7 | assert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.' 8 | %} 9 | if (value == 0) { 10 | // If value == 0, add an unsatisfiable requirement. 11 | value = 1; 12 | } 13 | 14 | return (); 15 | } 16 | 17 | func main() { 18 | assert_not_zero(1); 19 | assert_not_zero(-1); 20 | let x = 500 * 5; 21 | assert_not_zero(x); 22 | tempvar y = -80; 23 | assert_not_zero(y); 24 | 25 | assert_not_zero_manual_implementation(1); 26 | assert_not_zero_manual_implementation(-1); 27 | assert_not_zero_manual_implementation(x); 28 | assert_not_zero_manual_implementation(y); 29 | 30 | return (); 31 | } 32 | -------------------------------------------------------------------------------- /cairo_programs/big_struct.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.dict import DictAccess 2 | 3 | struct VotingState { 4 | n_yes_votes: felt, 5 | n_no_votes: felt, 6 | public_key_tree_start: DictAccess*, 7 | public_key_tree_end: DictAccess*, 8 | } 9 | 10 | struct VoteInfo { 11 | voter_id: felt, 12 | pub_key: felt, 13 | vote: felt, 14 | r: felt, 15 | s: felt, 16 | } 17 | 18 | struct BatchOutput { 19 | n_yes_votes: felt, 20 | n_no_votes: felt, 21 | public_keys_root_before: felt, 22 | public_keys_root_after: felt, 23 | } 24 | 25 | func main{}() { 26 | ret; 27 | } 28 | -------------------------------------------------------------------------------- /cairo_programs/bitwise_builtin_test.cairo: -------------------------------------------------------------------------------- 1 | %builtins bitwise 2 | from starkware.cairo.common.bitwise import bitwise_and, bitwise_xor, bitwise_or, bitwise_operations 3 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 4 | 5 | func main{bitwise_ptr: BitwiseBuiltin*}() { 6 | let (and_a) = bitwise_and(12, 10); // Binary (1100, 1010). 7 | assert and_a = 8; // Binary 1000. 8 | let (xor_a) = bitwise_xor(12, 10); 9 | assert xor_a = 6; 10 | let (or_a) = bitwise_or(12, 10); 11 | assert or_a = 14; 12 | 13 | let (and_b, xor_b, or_b) = bitwise_operations(9, 3); 14 | assert and_b = 1; 15 | assert xor_b = 10; 16 | assert or_b = 11; 17 | return (); 18 | } 19 | -------------------------------------------------------------------------------- /cairo_programs/bitwise_output.cairo: -------------------------------------------------------------------------------- 1 | %builtins output bitwise 2 | from starkware.cairo.common.bitwise import bitwise_and 3 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 4 | from starkware.cairo.common.serialize import serialize_word 5 | 6 | func main{output_ptr: felt*, bitwise_ptr: BitwiseBuiltin*}() { 7 | let (result) = bitwise_and(1, 2); 8 | serialize_word(result); 9 | return (); 10 | } 11 | -------------------------------------------------------------------------------- /cairo_programs/bitwise_recursion.cairo: -------------------------------------------------------------------------------- 1 | %builtins output range_check bitwise 2 | 3 | from starkware.cairo.common.bitwise import bitwise_and, bitwise_or, bitwise_xor 4 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 5 | from starkware.cairo.common.serialize import serialize_word 6 | 7 | func distort_value{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}( 8 | value: felt, secondary_value: felt, loop_num: felt 9 | ) -> (r: felt) { 10 | if (loop_num == 0) { 11 | return (value,); 12 | } 13 | 14 | // Check that 0 <= secondary_value < 2**64. 15 | [range_check_ptr] = secondary_value; 16 | assert [range_check_ptr + 1] = 2 ** 64 - 1 - secondary_value; 17 | let range_check_ptr = range_check_ptr + 2; 18 | 19 | let (distorted_value_a) = bitwise_xor(value, secondary_value); 20 | let (distorted_value_b) = bitwise_or(value, secondary_value / 2); 21 | let (distorted_value) = bitwise_and(distorted_value_a, distorted_value_b); 22 | 23 | return distort_value(distorted_value, secondary_value * 3, loop_num - 1); 24 | } 25 | 26 | func main{output_ptr: felt*, range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { 27 | let (result) = distort_value(45678783924002957984, 12546479, 20); 28 | assert result = 45673807582400916561; 29 | serialize_word(result); 30 | return (); 31 | } 32 | -------------------------------------------------------------------------------- /cairo_programs/blake2s_felts.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check bitwise 2 | 3 | from starkware.cairo.common.bool import TRUE, FALSE 4 | from starkware.cairo.common.alloc import alloc 5 | from starkware.cairo.common.cairo_blake2s.blake2s import blake2s_felts 6 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 7 | 8 | func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { 9 | alloc_locals; 10 | let inputs: felt* = alloc(); 11 | assert inputs[0] = 3456722; 12 | assert inputs[1] = 435425528; 13 | assert inputs[2] = 3232553; 14 | assert inputs[3] = 2576195; 15 | assert inputs[4] = 73471943; 16 | assert inputs[5] = 17549868; 17 | assert inputs[6] = 87158958; 18 | assert inputs[7] = 6353668; 19 | assert inputs[8] = 343656565; 20 | assert inputs[9] = 1255962; 21 | assert inputs[10] = 25439785; 22 | assert inputs[11] = 1154578; 23 | assert inputs[12] = 585849303; 24 | assert inputs[13] = 763502; 25 | assert inputs[14] = 43753647; 26 | assert inputs[15] = 74256930; 27 | let (local blake2s_ptr_start) = alloc(); 28 | let blake2s_ptr = blake2s_ptr_start; 29 | 30 | // Bigendian 31 | let (result) = blake2s_felts{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}( 32 | 16, inputs, TRUE 33 | ); 34 | assert result.low = 23022179997536219430502258022509199703; 35 | assert result.high = 136831746058902715979837770794974289597; 36 | 37 | // Little endian 38 | let (result) = blake2s_felts{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}( 39 | 16, inputs, FALSE 40 | ); 41 | assert result.low = 315510691254085211243916597439546947220; 42 | assert result.high = 42237338665522721102428636006748876126; 43 | 44 | return (); 45 | } 46 | -------------------------------------------------------------------------------- /cairo_programs/blake2s_hello_world_hash.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check bitwise 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.cairo_blake2s.blake2s import blake2s 5 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 6 | 7 | // Computes the hash of "Hello World" 8 | func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { 9 | alloc_locals; 10 | let inputs: felt* = alloc(); 11 | assert inputs[0] = 'Hell'; 12 | assert inputs[1] = 'o Wo'; 13 | assert inputs[2] = 'rld'; 14 | let (local blake2s_ptr_start) = alloc(); 15 | let blake2s_ptr = blake2s_ptr_start; 16 | let (output) = blake2s{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}(inputs, 9); 17 | assert output.low = 219917655069954262743903159041439073909; 18 | assert output.high = 296157033687865319468534978667166017272; 19 | return (); 20 | } 21 | -------------------------------------------------------------------------------- /cairo_programs/blake2s_integration_tests.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check bitwise 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.cairo_blake2s.blake2s import blake2s, finalize_blake2s, blake2s_felts 5 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 6 | from starkware.cairo.common.uint256 import Uint256 7 | from starkware.cairo.common.bool import TRUE 8 | 9 | func fill_array(array: felt*, base: felt, step: felt, array_length: felt, iterator: felt) { 10 | if (iterator == array_length) { 11 | return (); 12 | } 13 | assert array[iterator] = base + step * iterator; 14 | return fill_array(array, base, step, array_length, iterator + 1); 15 | } 16 | 17 | func test_integration{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(iter: felt, last: felt) { 18 | alloc_locals; 19 | if (iter == last) { 20 | return (); 21 | } 22 | 23 | let (data: felt*) = alloc(); 24 | fill_array(data, iter, 2 * iter, 10, 0); 25 | 26 | let (local blake2s_ptr_start) = alloc(); 27 | let blake2s_ptr = blake2s_ptr_start; 28 | let (res_1: Uint256) = blake2s{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}( 29 | data, 9 30 | ); 31 | 32 | finalize_blake2s(blake2s_ptr_start, blake2s_ptr); 33 | 34 | let (local blake2s_ptr_start) = alloc(); 35 | let blake2s_ptr = blake2s_ptr_start; 36 | 37 | let (data_2: felt*) = alloc(); 38 | assert data_2[0] = res_1.low; 39 | assert data_2[1] = res_1.high; 40 | 41 | let (res_2) = blake2s_felts{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}( 42 | 2, data_2, TRUE 43 | ); 44 | 45 | finalize_blake2s(blake2s_ptr_start, blake2s_ptr); 46 | 47 | if (iter == last - 1 and last == 10) { 48 | assert res_1.low = 327684140823325841083166505949840946643; 49 | assert res_1.high = 28077572547397067729112288485703133566; 50 | assert res_2.low = 323710308182296053867309835081443411626; 51 | assert res_2.high = 159988406782415793602959692147600111481; 52 | } 53 | 54 | if (iter == last - 1 and last == 100) { 55 | assert res_1.low = 26473789897582596397897414631405692327; 56 | assert res_1.high = 35314462001555260569814614879256292984; 57 | assert res_2.low = 256911263205530722270005922452382996929; 58 | assert res_2.high = 248798531786594770765531047659644061441; 59 | } 60 | 61 | return test_integration(iter + 1, last); 62 | } 63 | 64 | func run_tests{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(last: felt) { 65 | alloc_locals; 66 | test_integration(0, last); 67 | 68 | return (); 69 | } 70 | 71 | func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { 72 | run_tests(10); 73 | 74 | return (); 75 | } 76 | -------------------------------------------------------------------------------- /cairo_programs/cairo_keccak.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check bitwise 2 | 3 | from starkware.cairo.common.cairo_keccak.keccak import cairo_keccak, finalize_keccak 4 | from starkware.cairo.common.uint256 import Uint256 5 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 6 | from starkware.cairo.common.alloc import alloc 7 | 8 | func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { 9 | alloc_locals; 10 | 11 | let (keccak_ptr: felt*) = alloc(); 12 | let keccak_ptr_start = keccak_ptr; 13 | 14 | let (inputs: felt*) = alloc(); 15 | 16 | assert inputs[0] = 8031924123371070792; 17 | assert inputs[1] = 560229490; 18 | 19 | let n_bytes = 16; 20 | 21 | let (res: Uint256) = cairo_keccak{keccak_ptr=keccak_ptr}(inputs=inputs, n_bytes=n_bytes); 22 | 23 | assert res.low = 293431514620200399776069983710520819074; 24 | assert res.high = 317109767021952548743448767588473366791; 25 | 26 | finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr); 27 | 28 | return (); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /cairo_programs/call_function_assign_param_by_name.cairo: -------------------------------------------------------------------------------- 1 | func a{}(arg: felt) { 2 | [ap] = arg, ap++; 3 | ret; 4 | } 5 | 6 | func b{}(first_arg: felt, second_arg: felt) { 7 | [ap] = first_arg + second_arg, ap++; 8 | ret; 9 | } 10 | 11 | func main{}() { 12 | a(arg=1); 13 | b(first_arg=1, second_arg=2); 14 | 15 | return (); 16 | } 17 | -------------------------------------------------------------------------------- /cairo_programs/common_signature.cairo: -------------------------------------------------------------------------------- 1 | %builtins ecdsa 2 | from starkware.cairo.common.cairo_builtins import SignatureBuiltin 3 | from starkware.cairo.common.signature import verify_ecdsa_signature 4 | 5 | func main{ecdsa_ptr: SignatureBuiltin*}() { 6 | verify_ecdsa_signature( 7 | 2718, 8 | 1735102664668487605176656616876767369909409133946409161569774794110049207117, 9 | 3086480810278599376317923499561306189851900463386393948998357832163236918254, 10 | 598673427589502599949712887611119751108407514580626464031881322743364689811, 11 | ); 12 | return (); 13 | } 14 | -------------------------------------------------------------------------------- /cairo_programs/dict.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.dict import dict_read, dict_write 2 | from starkware.cairo.common.default_dict import default_dict_new 3 | from starkware.cairo.common.dict_access import DictAccess 4 | 5 | func main() { 6 | alloc_locals; 7 | let (local my_dict: DictAccess*) = default_dict_new(17); 8 | dict_write{dict_ptr=my_dict}(key=12, new_value=34); 9 | let (local val1: felt) = dict_read{dict_ptr=my_dict}(key=12); 10 | assert val1 = 34; 11 | let (local val2: felt) = dict_read{dict_ptr=my_dict}(key=11); 12 | assert val2 = 17; 13 | let (local val3: felt) = dict_read{dict_ptr=my_dict}(key=12); 14 | assert val3 = 34; 15 | let (local val4: felt) = dict_read{dict_ptr=my_dict}(key=11); 16 | assert val4 = 17; 17 | dict_write{dict_ptr=my_dict}(key=11, new_value=35); 18 | let (local val5: felt) = dict_read{dict_ptr=my_dict}(key=11); 19 | assert val5 = 35; 20 | dict_write{dict_ptr=my_dict}(key=12, new_value=35); 21 | let (local val6: felt) = dict_read{dict_ptr=my_dict}(key=11); 22 | assert val6 = 35; 23 | dict_write{dict_ptr=my_dict}(key=20, new_value=-5); 24 | let (local val6: felt) = dict_read{dict_ptr=my_dict}(key=20); 25 | assert val6 = -5; 26 | return (); 27 | } 28 | -------------------------------------------------------------------------------- /cairo_programs/dict_squash.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.dict_access import DictAccess 4 | from starkware.cairo.common.dict import dict_write, dict_update, dict_squash 5 | from starkware.cairo.common.default_dict import default_dict_new 6 | 7 | func main{range_check_ptr}() -> () { 8 | let (dict_start) = default_dict_new(17); 9 | let dict_end = dict_start; 10 | dict_write{dict_ptr=dict_end}(0, 1); 11 | dict_write{dict_ptr=dict_end}(1, 10); 12 | dict_write{dict_ptr=dict_end}(2, -2); 13 | dict_update{dict_ptr=dict_end}(0, 1, 2); 14 | dict_update{dict_ptr=dict_end}(0, 2, 3); 15 | dict_update{dict_ptr=dict_end}(0, 3, 4); 16 | dict_update{dict_ptr=dict_end}(1, 10, 15); 17 | dict_update{dict_ptr=dict_end}(1, 15, 20); 18 | dict_update{dict_ptr=dict_end}(1, 20, 25); 19 | dict_update{dict_ptr=dict_end}(2, -2, -4); 20 | dict_update{dict_ptr=dict_end}(2, -4, -8); 21 | dict_update{dict_ptr=dict_end}(2, -8, -16); 22 | let (squashed_dict_start, squashed_dict_end) = dict_squash{range_check_ptr=range_check_ptr}( 23 | dict_start, dict_end 24 | ); 25 | assert squashed_dict_end[0] = DictAccess(key=0, prev_value=1, new_value=4); 26 | assert squashed_dict_end[1] = DictAccess(key=1, prev_value=10, new_value=25); 27 | assert squashed_dict_end[2] = DictAccess(key=2, prev_value=-2, new_value=-16); 28 | return (); 29 | } 30 | -------------------------------------------------------------------------------- /cairo_programs/dict_update.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.dict import dict_read, dict_write, dict_update 2 | from starkware.cairo.common.default_dict import default_dict_new 3 | from starkware.cairo.common.dict_access import DictAccess 4 | 5 | func main() { 6 | alloc_locals; 7 | // Create default dict 8 | let (local my_dict: DictAccess*) = default_dict_new(17); 9 | // Write value 10 | dict_write{dict_ptr=my_dict}(key=12, new_value=34); 11 | let (local val1: felt) = dict_read{dict_ptr=my_dict}(key=12); 12 | assert val1 = 34; 13 | // Update written value 14 | dict_update{dict_ptr=my_dict}(key=12, prev_value=34, new_value=49); 15 | let (local val2: felt) = dict_read{dict_ptr=my_dict}(key=12); 16 | assert val2 = 49; 17 | // Update value that doesnt exixt yet, using default value as prev_value 18 | dict_update{dict_ptr=my_dict}(key=10, prev_value=17, new_value=22); 19 | let (local val3: felt) = dict_read{dict_ptr=my_dict}(key=10); 20 | assert val3 = 22; 21 | dict_update{dict_ptr=my_dict}(key=10, prev_value=22, new_value=-8); 22 | let (local val4: felt) = dict_read{dict_ptr=my_dict}(key=10); 23 | assert val4 = -8; 24 | return (); 25 | } 26 | -------------------------------------------------------------------------------- /cairo_programs/ec_double_assign.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | from starkware.cairo.common.cairo_secp.bigint import BigInt3, nondet_bigint3 3 | struct EcPoint { 4 | x: BigInt3, 5 | y: BigInt3, 6 | } 7 | 8 | func ec_double{range_check_ptr}(point: EcPoint, slope: BigInt3) -> (res: BigInt3) { 9 | %{ 10 | from starkware.cairo.common.cairo_secp.secp_utils import pack 11 | SECP_P = 2**255-19 12 | 13 | slope = pack(ids.slope, PRIME) 14 | x = pack(ids.point.x, PRIME) 15 | y = pack(ids.point.y, PRIME) 16 | 17 | value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P 18 | %} 19 | 20 | let (new_x: BigInt3) = nondet_bigint3(); 21 | return (res=new_x); 22 | } 23 | 24 | func main{range_check_ptr}() { 25 | let p = EcPoint(BigInt3(1,2,3), BigInt3(4,5,6)); 26 | let s = BigInt3(7,8,9); 27 | let (res) = ec_double(p, s); 28 | assert res.d0 = 21935; 29 | assert res.d1 = 12420; 30 | assert res.d2 = 184; 31 | return (); 32 | } 33 | -------------------------------------------------------------------------------- /cairo_programs/factorial.cairo: -------------------------------------------------------------------------------- 1 | // factorial(n) = n! 2 | func factorial(n) -> (result: felt) { 3 | if (n == 1) { 4 | return (n,); 5 | } 6 | let (a) = factorial(n - 1); 7 | return (n * a,); 8 | } 9 | 10 | func main() { 11 | // Make sure the factorial(10) == 3628800 12 | let (y) = factorial(10); 13 | y = 3628800; 14 | return (); 15 | } 16 | -------------------------------------------------------------------------------- /cairo_programs/fibonacci.cairo: -------------------------------------------------------------------------------- 1 | func main() { 2 | // Call fib(1, 1, 10). 3 | let result: felt = fib(1, 1, 10); 4 | 5 | // Make sure the 10th Fibonacci number is 144. 6 | assert result = 144; 7 | ret; 8 | } 9 | 10 | func fib(first_element, second_element, n) -> (res: felt) { 11 | jmp fib_body if n != 0; 12 | tempvar result = second_element; 13 | return (second_element,); 14 | 15 | fib_body: 16 | tempvar y = first_element + second_element; 17 | return fib(second_element, y, n - 1); 18 | } 19 | -------------------------------------------------------------------------------- /cairo_programs/finalize_blake2s.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check bitwise 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.cairo_blake2s.blake2s import blake2s, finalize_blake2s 5 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 6 | 7 | func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { 8 | alloc_locals; 9 | let inputs: felt* = alloc(); 10 | assert inputs[0] = 'Hell'; 11 | assert inputs[1] = 'o Wo'; 12 | assert inputs[2] = 'rld'; 13 | let (local blake2s_ptr_start) = alloc(); 14 | let blake2s_ptr = blake2s_ptr_start; 15 | let (output) = blake2s{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}(inputs, 9); 16 | finalize_blake2s(blake2s_ptr_start, blake2s_ptr); 17 | return (); 18 | } 19 | -------------------------------------------------------------------------------- /cairo_programs/finalize_blake2s_v2.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check bitwise 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.cairo_blake2s.blake2s import blake2s, _finalize_blake2s_inner, _get_sigma, INSTANCE_SIZE, INPUT_BLOCK_FELTS 5 | from starkware.cairo.common.cairo_blake2s.packed_blake2s import N_PACKED_INSTANCES, blake2s_compress 6 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 7 | from starkware.cairo.common.registers import get_fp_and_pc 8 | from starkware.cairo.common.math import assert_nn_le, split_felt, unsigned_div_rem 9 | 10 | const BLAKE2S_INPUT_CHUNK_SIZE_FELTS = INPUT_BLOCK_FELTS; 11 | 12 | // Verifies that the results of blake2s() are valid. 13 | func finalize_blake2s{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( 14 | blake2s_ptr_start: felt*, blake2s_ptr_end: felt* 15 | ) { 16 | alloc_locals; 17 | 18 | let (__fp__, _) = get_fp_and_pc(); 19 | 20 | let (sigma) = _get_sigma(); 21 | 22 | tempvar n = (blake2s_ptr_end - blake2s_ptr_start) / INSTANCE_SIZE; 23 | if (n == 0) { 24 | return (); 25 | } 26 | 27 | %{ 28 | # Add dummy pairs of input and output. 29 | from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress 30 | 31 | _n_packed_instances = int(ids.N_PACKED_INSTANCES) 32 | assert 0 <= _n_packed_instances < 20 33 | _blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS) 34 | assert 0 <= _blake2s_input_chunk_size_felts < 100 35 | 36 | message = [0] * _blake2s_input_chunk_size_felts 37 | modified_iv = [IV[0] ^ 0x01010020] + IV[1:] 38 | output = blake2s_compress( 39 | message=message, 40 | h=modified_iv, 41 | t0=0, 42 | t1=0, 43 | f0=0xffffffff, 44 | f1=0, 45 | ) 46 | padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1) 47 | segments.write_arg(ids.blake2s_ptr_end, padding) 48 | %} 49 | 50 | // Compute the amount of chunks (rounded up). 51 | let (local n_chunks, _) = unsigned_div_rem(n + N_PACKED_INSTANCES - 1, N_PACKED_INSTANCES); 52 | let blake2s_ptr = blake2s_ptr_start; 53 | _finalize_blake2s_inner{blake2s_ptr=blake2s_ptr}(n=n_chunks, sigma=sigma); 54 | return (); 55 | } 56 | 57 | func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { 58 | alloc_locals; 59 | let inputs: felt* = alloc(); 60 | assert inputs[0] = 'Hell'; 61 | assert inputs[1] = 'o Wo'; 62 | assert inputs[2] = 'rld'; 63 | let (local blake2s_ptr_start) = alloc(); 64 | let blake2s_ptr = blake2s_ptr_start; 65 | let (output) = blake2s{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}(inputs, 9); 66 | finalize_blake2s(blake2s_ptr_start, blake2s_ptr); 67 | return (); 68 | } 69 | -------------------------------------------------------------------------------- /cairo_programs/find_element.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | from starkware.cairo.common.find_element import find_element 3 | from starkware.cairo.common.alloc import alloc 4 | 5 | struct MyStruct { 6 | a: felt, 7 | b: felt, 8 | } 9 | 10 | func main{range_check_ptr}() -> () { 11 | // Create an array with MyStruct elements (1,2), (3,4), (5,6). 12 | alloc_locals; 13 | let (local array_ptr: MyStruct*) = alloc(); 14 | assert array_ptr[0] = MyStruct(a=1, b=2); 15 | assert array_ptr[1] = MyStruct(a=3, b=4); 16 | assert array_ptr[2] = MyStruct(a=5, b=6); 17 | 18 | // Find any element with key '5'. 19 | let (element_ptr: MyStruct*) = find_element( 20 | array_ptr=array_ptr, elm_size=MyStruct.SIZE, n_elms=3, key=5 21 | ); 22 | // A pointer to the element with index 2 is returned. 23 | assert element_ptr.a = 5; 24 | assert element_ptr.b = 6; 25 | 26 | return (); 27 | } 28 | -------------------------------------------------------------------------------- /cairo_programs/function_return.cairo: -------------------------------------------------------------------------------- 1 | func a{}() -> (b: felt) { 2 | return (5,); 3 | } 4 | 5 | func main{}() { 6 | a(); 7 | ret; 8 | } 9 | -------------------------------------------------------------------------------- /cairo_programs/function_return_if_print.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | func a{}() -> (b: felt) { 6 | return (5,); 7 | } 8 | 9 | func main{output_ptr: felt*}() { 10 | a(); 11 | if ([ap - 1] == 5) { 12 | serialize_word(5); 13 | return (); 14 | } else { 15 | serialize_word(10); 16 | } 17 | return (); 18 | } 19 | -------------------------------------------------------------------------------- /cairo_programs/function_return_to_variable.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | func return_10() -> (res: felt) { 6 | let res = 10; 7 | return (res,); 8 | } 9 | 10 | func main{output_ptr: felt*}() { 11 | let (value) = return_10(); 12 | 13 | serialize_word(value); 14 | 15 | return (); 16 | } 17 | -------------------------------------------------------------------------------- /cairo_programs/if_and_prime.cairo: -------------------------------------------------------------------------------- 1 | func main{}() { 2 | [ap] = 3618502788666131213697322783095070105623107215331596699973092056135872020431, ap++; 3 | [ap] = -50, ap++; 4 | 5 | if ([ap - 1] == [ap - 2]) { 6 | [ap] = 10, ap++; 7 | } else { 8 | [ap] = 5, ap++; 9 | } 10 | ret; 11 | } 12 | -------------------------------------------------------------------------------- /cairo_programs/if_in_function.cairo: -------------------------------------------------------------------------------- 1 | func a{}() { 2 | [ap] = 5, ap++; 3 | 4 | if ([ap - 1] == 2) { 5 | [ap] = [ap - 1] + 3, ap++; 6 | } else { 7 | [ap] = 10, ap++; 8 | } 9 | ret; 10 | } 11 | 12 | func main{}() { 13 | a(); 14 | 15 | ret; 16 | } 17 | -------------------------------------------------------------------------------- /cairo_programs/if_list.cairo: -------------------------------------------------------------------------------- 1 | func main{}() { 2 | [ap] = 3, ap++; 3 | 4 | // 5 | 6 | if (50 == 3) { 7 | [ap] = [ap - 1], ap++; 8 | } else { 9 | [ap] = 2, ap++; 10 | } 11 | 12 | // 13 | 14 | if (50 - [ap - 1] == 3) { 15 | [ap] = [ap - 1], ap++; 16 | } else { 17 | [ap] = 2, ap++; 18 | } 19 | 20 | // 21 | 22 | if ([ap - 1] - 50 == 3) { 23 | [ap] = 25, ap++; 24 | } else { 25 | [ap] = 2, ap++; 26 | } 27 | 28 | // 29 | 30 | if ([ap - 1] + 50 == 3) { 31 | [ap] = 25, ap++; 32 | } else { 33 | [ap] = 2, ap++; 34 | } 35 | 36 | // 37 | 38 | if (10 + 50 == 3) { 39 | [ap] = 25, ap++; 40 | } else { 41 | [ap] = 2, ap++; 42 | } 43 | 44 | // 45 | 46 | if ([fp + 2] - [ap - 6] == 3) { 47 | [ap] = 25, ap++; 48 | } else { 49 | [ap] = 2, ap++; 50 | } 51 | 52 | // 53 | 54 | ret; 55 | } 56 | -------------------------------------------------------------------------------- /cairo_programs/if_reloc_equal.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.alloc import alloc 2 | 3 | func main{}() { 4 | let arr: felt* = alloc(); 5 | 6 | assert arr[0] = 1; 7 | assert arr[5] = 2; 8 | 9 | let end = arr + 5; 10 | 11 | if (arr == end) { 12 | ret; 13 | } 14 | 15 | ret; 16 | } 17 | -------------------------------------------------------------------------------- /cairo_programs/is_quad_residue.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | from starkware.cairo.common.serialize import serialize_word 3 | from starkware.cairo.common.math import is_quad_residue 4 | from starkware.cairo.common.alloc import alloc 5 | 6 | func fill_array(array_start: felt*, iter: felt) -> () { 7 | if (iter == 8) { 8 | return (); 9 | } 10 | assert array_start[iter] = iter; 11 | return fill_array(array_start, iter + 1); 12 | } 13 | 14 | func check_quad_res{output_ptr: felt*}(inputs: felt*, expected: felt*, iter: felt) { 15 | if (iter == 8) { 16 | return (); 17 | } 18 | serialize_word(inputs[iter]); 19 | serialize_word(expected[iter]); 20 | 21 | assert is_quad_residue(inputs[iter]) = expected[iter]; 22 | return check_quad_res(inputs, expected, iter + 1); 23 | } 24 | 25 | func main{output_ptr: felt*}() { 26 | alloc_locals; 27 | let (inputs: felt*) = alloc(); 28 | fill_array(inputs, 0); 29 | 30 | let (expected: felt*) = alloc(); 31 | assert expected[0] = 1; 32 | assert expected[1] = 1; 33 | assert expected[2] = 1; 34 | assert expected[3] = 0; 35 | assert expected[4] = 1; 36 | assert expected[5] = 1; 37 | assert expected[6] = 0; 38 | assert expected[7] = 1; 39 | 40 | check_quad_res(inputs, expected, 0); 41 | 42 | return (); 43 | } 44 | -------------------------------------------------------------------------------- /cairo_programs/jmp.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | func main{output_ptr: felt*}() { 6 | jmp test; 7 | 8 | [ap] = 1, ap++; 9 | jmp rel 6; 10 | 11 | test: 12 | [ap] = 2, ap++; 13 | 14 | serialize_word([ap - 1]); 15 | return (); 16 | } 17 | -------------------------------------------------------------------------------- /cairo_programs/jmp_if_condition.cairo: -------------------------------------------------------------------------------- 1 | func foo(n) -> (r: felt) { 2 | alloc_locals; 3 | local x; 4 | 5 | jmp body if n != 0; 6 | [ap] = 0, ap++; 7 | ret; 8 | 9 | body: 10 | [ap] = 1, ap++; 11 | ret; 12 | } 13 | 14 | func main() { 15 | foo(n=0); 16 | ret; 17 | } 18 | -------------------------------------------------------------------------------- /cairo_programs/keccak_add_uint256.cairo: -------------------------------------------------------------------------------- 1 | %builtins output range_check bitwise 2 | 3 | from starkware.cairo.common.keccak_utils.keccak_utils import keccak_add_uint256 4 | from starkware.cairo.common.uint256 import Uint256 5 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 6 | from starkware.cairo.common.alloc import alloc 7 | from starkware.cairo.common.serialize import serialize_word 8 | 9 | func main{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { 10 | alloc_locals; 11 | 12 | let (inputs) = alloc(); 13 | let inputs_start = inputs; 14 | 15 | let num = Uint256(34623634663146736, 598249824422424658356); 16 | 17 | keccak_add_uint256{inputs=inputs_start}(num=num, bigend=0); 18 | 19 | assert inputs[0] = 34623634663146736; 20 | assert inputs[1] = 0; 21 | assert inputs[2] = 7954014063719006644; 22 | assert inputs[3] = 32; 23 | 24 | serialize_word(inputs[0]); 25 | serialize_word(inputs[1]); 26 | serialize_word(inputs[2]); 27 | serialize_word(inputs[3]); 28 | 29 | return (); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /cairo_programs/keccak_builtin.cairo: -------------------------------------------------------------------------------- 1 | %builtins keccak 2 | from starkware.cairo.common.cairo_builtins import KeccakBuiltin 3 | from starkware.cairo.common.keccak_state import KeccakBuiltinState 4 | 5 | func main{keccak_ptr: KeccakBuiltin*}() { 6 | assert keccak_ptr[0].input = KeccakBuiltinState(1, 2, 3, 4, 5, 6, 7, 8); 7 | let result = keccak_ptr[0].output; 8 | let keccak_ptr = keccak_ptr + KeccakBuiltin.SIZE; 9 | assert result.s0 = 528644516554364142278482415480021626364691973678134577961206; 10 | assert result.s1 = 768681319646568210457759892191562701823009052229295869963057; 11 | assert result.s2 = 1439835513376369408063324968379272676079109225238241190228026; 12 | assert result.s3 = 1150396629165612276474514703759718478742374517669870754478270; 13 | assert result.s4 = 1515147102575186161827863034255579930572231617017100845406254; 14 | assert result.s5 = 1412568161597072838250338588041800080889949791225997426843744; 15 | assert result.s6 = 982235455376248641031519404605670648838699214888770304613539; 16 | assert result.s7 = 1339947803093378278438908448344904300127577306141693325151040; 17 | return (); 18 | } 19 | -------------------------------------------------------------------------------- /cairo_programs/math_cmp.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math_cmp import ( 4 | is_not_zero, 5 | is_nn, 6 | is_le, 7 | is_nn_le, 8 | is_in_range, 9 | is_le_felt, 10 | ) 11 | 12 | func main{range_check_ptr: felt}() { 13 | // is_not_zero 14 | let a = is_not_zero(10); 15 | assert a = 1; 16 | let b = is_not_zero(1); 17 | assert b = 1; 18 | let c = is_not_zero(0); 19 | assert c = 0; 20 | 21 | // is_nn 22 | let d = is_nn(0); 23 | assert d = 1; 24 | let e = is_nn(88); 25 | assert e = 1; 26 | let f = is_nn(-88); 27 | assert f = 0; 28 | 29 | // is_le 30 | let g = is_le(1, 2); 31 | assert g = 1; 32 | let h = is_le(2, 2); 33 | assert h = 1; 34 | let i = is_le(56, 20); 35 | assert i = 0; 36 | 37 | // is_nn_le 38 | let j = is_nn_le(1, 2); 39 | assert j = 1; 40 | let k = is_nn_le(2, 2); 41 | assert k = 1; 42 | let l = is_nn_le(56, 20); 43 | assert l = 0; 44 | 45 | // is_in_range 46 | let m = is_in_range(1, 2, 3); 47 | assert m = 0; 48 | let n = is_in_range(2, 2, 5); 49 | assert n = 1; 50 | let o = is_in_range(56, 20, 120); 51 | assert o = 1; 52 | 53 | // TODO: Uncomment once ASSERT_LE_FELT hint is implemented 54 | // is_le_felt 55 | // let p = is_le_felt(1, 2); 56 | // assert p = 1; 57 | // let q = is_le_felt(2, 2); 58 | // assert q = 1; 59 | // let r = is_le_felt(56, 20); 60 | // assert r = 0; 61 | 62 | return (); 63 | } 64 | -------------------------------------------------------------------------------- /cairo_programs/memcpy_test.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.alloc import alloc 2 | from starkware.cairo.common.memcpy import memcpy 3 | from starkware.cairo.common.registers import get_fp_and_pc 4 | 5 | func main() { 6 | alloc_locals; 7 | 8 | let (__fp__, _) = get_fp_and_pc(); 9 | 10 | local numbers: (felt, felt, felt) = (1, 2, 3); 11 | 12 | let dest: felt* = alloc(); 13 | 14 | memcpy(dst=dest, src=&numbers, len=3); 15 | 16 | assert numbers[0] = dest[0]; 17 | assert numbers[1] = dest[1]; 18 | assert numbers[2] = dest[2]; 19 | 20 | return (); 21 | } 22 | -------------------------------------------------------------------------------- /cairo_programs/memory_holes.cairo: -------------------------------------------------------------------------------- 1 | func main() { 2 | // Deliberately create memory holes 3 | assert [ap + 5] = 1; 4 | return (); 5 | } 6 | -------------------------------------------------------------------------------- /cairo_programs/memset.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.alloc import alloc 2 | from starkware.cairo.common.memset import memset 3 | from starkware.cairo.common.bool import TRUE, FALSE 4 | 5 | func check_array(array: felt*, value: felt, array_length: felt, iterator: felt) -> (r: felt) { 6 | if (iterator == array_length) { 7 | return (TRUE,); 8 | } 9 | if (array[iterator] != value) { 10 | return (FALSE,); 11 | } 12 | return check_array(array, value, array_length, iterator + 1); 13 | } 14 | 15 | func main() { 16 | alloc_locals; 17 | let (local strings: felt*) = alloc(); 18 | memset(strings, 'Lambda', 20); 19 | let check_string: felt = check_array(strings, 'Lambda', 20, 0); 20 | assert check_string = TRUE; 21 | assert strings[20] = 'can insert new value'; 22 | 23 | let numbers: felt* = alloc(); 24 | memset(numbers, 10, 100); 25 | let check_string: felt = check_array(numbers, 10, 100, 0); 26 | assert check_string = TRUE; 27 | assert numbers[100] = 11; 28 | 29 | return (); 30 | } 31 | -------------------------------------------------------------------------------- /cairo_programs/multiplicative_inverse.cairo: -------------------------------------------------------------------------------- 1 | func main() { 2 | [ap + 0] = 11, ap++; 3 | [ap + 0] = 1000, ap++; 4 | [ap - 1] = [ap + 0] * [ap - 2], ap++; 5 | 6 | [ap + 0] = 1, ap++; 7 | [ap + 0] = 2, ap++; 8 | [ap - 2] = [ap + 0] * [ap - 1], ap++; 9 | 10 | return (); 11 | } 12 | -------------------------------------------------------------------------------- /cairo_programs/not_main.cairo: -------------------------------------------------------------------------------- 1 | func not_main() { 2 | [ap] = 123; 3 | ret; 4 | } 5 | 6 | func main() { 7 | ret; 8 | } 9 | -------------------------------------------------------------------------------- /cairo_programs/pedersen_and_bitwise_builtins.cairo: -------------------------------------------------------------------------------- 1 | %builtins output pedersen range_check bitwise 2 | 3 | from starkware.cairo.common.cairo_builtins import HashBuiltin 4 | from starkware.cairo.common.hash import hash2 5 | from starkware.cairo.common.bitwise import bitwise_and, bitwise_or, bitwise_xor 6 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 7 | from starkware.cairo.common.serialize import serialize_word 8 | 9 | func get_hash(hash_ptr: HashBuiltin*, num_a: felt, num_b: felt) -> ( 10 | hash_ptr: HashBuiltin*, r: felt 11 | ) { 12 | with hash_ptr { 13 | let (result) = hash2(num_a, num_b); 14 | } 15 | return (hash_ptr=hash_ptr, r=result); 16 | } 17 | 18 | func distort_value{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}( 19 | value: felt, secondary_value: felt, loop_num: felt 20 | ) -> (r: felt) { 21 | if (loop_num == 0) { 22 | return (value,); 23 | } 24 | 25 | // Check that 0 <= secondary_value < 2**64. 26 | [range_check_ptr] = secondary_value; 27 | assert [range_check_ptr + 1] = 2 ** 64 - 1 - secondary_value; 28 | let range_check_ptr = range_check_ptr + 2; 29 | 30 | let (distorted_value_a) = bitwise_xor(value, secondary_value); 31 | let (distorted_value_b) = bitwise_or(value, secondary_value / 2); 32 | let (distorted_value) = bitwise_and(distorted_value_a, distorted_value_b); 33 | 34 | return distort_value(distorted_value, secondary_value * 3, loop_num - 1); 35 | } 36 | 37 | func main{ 38 | output_ptr: felt*, 39 | pedersen_ptr: HashBuiltin*, 40 | range_check_ptr: felt, 41 | bitwise_ptr: BitwiseBuiltin*, 42 | }() { 43 | let num_a = 123568; 44 | let num_b = 5673940; 45 | let (distorted_num_b) = distort_value(num_b, 6783043740, 20); 46 | let (pedersen_ptr, result: felt) = get_hash(pedersen_ptr, num_a, distorted_num_b); 47 | assert result = 1705936988874506830037172232662562674195194978736118624789869153703579404549; 48 | serialize_word(result); 49 | return (); 50 | } 51 | -------------------------------------------------------------------------------- /cairo_programs/pedersen_and_bitwise_builtins_with_alloc_locals.cairo: -------------------------------------------------------------------------------- 1 | %builtins output pedersen range_check bitwise 2 | 3 | from starkware.cairo.common.cairo_builtins import HashBuiltin 4 | from starkware.cairo.common.hash import hash2 5 | from starkware.cairo.common.bitwise import bitwise_and, bitwise_or, bitwise_xor 6 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 7 | from starkware.cairo.common.serialize import serialize_word 8 | 9 | func get_distorted_pedersen{hash_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*}( 10 | num_a: felt, num_b: felt 11 | ) -> (r: felt) { 12 | let num_y: felt = bitwise_xor(num_a, num_b); 13 | let num_x: felt = bitwise_and(num_a, num_b); 14 | let pedersen_result: felt = hash2(num_x, num_y); 15 | return (pedersen_result,); 16 | } 17 | 18 | func distort_value{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}( 19 | value: felt, secondary_value: felt, loop_num: felt 20 | ) -> (r: felt) { 21 | if (loop_num == 0) { 22 | return (value,); 23 | } 24 | 25 | // Check that 0 <= secondary_value < 2**64. 26 | [range_check_ptr] = secondary_value; 27 | assert [range_check_ptr + 1] = 2 ** 64 - 1 - secondary_value; 28 | let range_check_ptr = range_check_ptr + 2; 29 | 30 | let distorted_value_a: felt = bitwise_xor(value, secondary_value); 31 | let distorted_value_b: felt = bitwise_or(value, secondary_value / 2); 32 | let distorted_value: felt = bitwise_and(distorted_value_a, distorted_value_b); 33 | 34 | return distort_value(distorted_value, secondary_value * 3, loop_num - 1); 35 | } 36 | 37 | func main{ 38 | output_ptr: felt*, 39 | pedersen_ptr: HashBuiltin*, 40 | range_check_ptr: felt, 41 | bitwise_ptr: BitwiseBuiltin*, 42 | }() { 43 | alloc_locals; 44 | tempvar num_a = 99; 45 | tempvar num_b = 105; 46 | let first_result: felt = get_distorted_pedersen{hash_ptr=pedersen_ptr}(num_a, num_b); 47 | let final_result: felt = distort_value(first_result, 17896542, 10); 48 | assert final_result = 1659553275753748707961758488122491333947144556174897006960881236685908158848; 49 | serialize_word(final_result); 50 | return (); 51 | } 52 | -------------------------------------------------------------------------------- /cairo_programs/pedersen_test.cairo: -------------------------------------------------------------------------------- 1 | %builtins output pedersen range_check 2 | 3 | from starkware.cairo.common.cairo_builtins import HashBuiltin 4 | from starkware.cairo.common.hash import hash2 5 | 6 | func main{output_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { 7 | let (seed) = hash2{hash_ptr=pedersen_ptr}(0, 0); 8 | assert [output_ptr] = seed; 9 | let output_ptr = output_ptr + 1; 10 | 11 | let (seed_2) = hash2{hash_ptr=pedersen_ptr}(234, 123897213); 12 | assert seed_2 = 2528904803005991377642213282618516374663011807602690623037041511517940816555; 13 | return (); 14 | } 15 | -------------------------------------------------------------------------------- /cairo_programs/pointers.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | struct MyClass { 6 | a: felt, 7 | b: felt, 8 | } 9 | 10 | func main{output_ptr: felt*}() { 11 | alloc_locals; 12 | 13 | local a: MyClass; 14 | a.a = 1; 15 | a.b = 2; 16 | 17 | let b = &a; 18 | 19 | serialize_word(b.b); 20 | 21 | return (); 22 | } 23 | -------------------------------------------------------------------------------- /cairo_programs/poseidon_builtin.cairo: -------------------------------------------------------------------------------- 1 | %builtins poseidon 2 | from starkware.cairo.common.cairo_builtins import PoseidonBuiltin 3 | from starkware.cairo.common.poseidon_state import PoseidonBuiltinState 4 | 5 | func main{poseidon_ptr: PoseidonBuiltin*}() { 6 | // Create an initial poseidon state with three felts 7 | assert poseidon_ptr[0].input = PoseidonBuiltinState(1, 2, 3); 8 | // Obtain the next poseidon state by deducing the next three memory cells 9 | let result = poseidon_ptr[0].output; 10 | let poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; 11 | // Check the vaues of the poseidon output 12 | assert result.s0 = 442682200349489646213731521593476982257703159825582578145778919623645026501; 13 | assert result.s1 = 2233832504250924383748553933071188903279928981104663696710686541536735838182; 14 | assert result.s2 = 2512222140811166287287541003826449032093371832913959128171347018667852712082; 15 | return (); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /cairo_programs/poseidon_hash.cairo: -------------------------------------------------------------------------------- 1 | %builtins poseidon 2 | from starkware.cairo.common.cairo_builtins import PoseidonBuiltin 3 | from starkware.cairo.common.poseidon_state import PoseidonBuiltinState 4 | from starkware.cairo.common.builtin_poseidon.poseidon import ( 5 | poseidon_hash, 6 | poseidon_hash_single, 7 | poseidon_hash_many, 8 | ) 9 | from starkware.cairo.common.alloc import alloc 10 | 11 | func main{poseidon_ptr: PoseidonBuiltin*}() { 12 | // Hash one 13 | let (x) = poseidon_hash_single( 14 | 218676008889449692916464780911713710628115973574242889792891157041292792362 15 | ); 16 | assert x = 2835120893146788752888137145656423078969524407843035783270702964188823073934; 17 | // Hash two 18 | let (y) = poseidon_hash(1253795, 18540013156130945068); 19 | assert y = 37282360750367388068593128053386029947772104009544220786084510532118246655; 20 | 21 | //TODO: Uncomment the following block once the hint "memory[ap] = to_felt_or_relocatable(ids.n >= 10)" is implemented 22 | // // Hash five 23 | // let felts: felt* = alloc(); 24 | // assert felts[0] = 84175983715088675913672849362079546; 25 | // assert felts[1] = 9384720329467203286234076408512594689579283578028960384690; 26 | // assert felts[2] = 291883989128409324823849293040390493094093; 27 | // assert felts[3] = 5849589438543859348593485948598349584395839402940940290490324; 28 | // assert felts[4] = 1836254780028456372728992049476335424263474849; 29 | // let (z) = poseidon_hash_many(5, felts); 30 | // assert z = 47102513329160951064697157194713013753695317629154835326726810042406974264; 31 | return (); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /cairo_programs/pow.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.pow import pow 4 | 5 | func main{range_check_ptr: felt}() { 6 | let (x) = pow(2, 3); 7 | assert x = 8; 8 | let (y) = pow(10, 6); 9 | assert y = 1000000; 10 | let (z) = pow(152, 25); 11 | assert z = 3516330588649452857943715400722794159857838650852114432; 12 | let (u) = pow(-2, 3); 13 | assert (u) = -8; 14 | let (v) = pow(-25, 31); 15 | assert (v) = -21684043449710088680149056017398834228515625; 16 | 17 | return (); 18 | } 19 | -------------------------------------------------------------------------------- /cairo_programs/print.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | func main{output_ptr: felt*}() { 6 | const MY_INT = 1234; 7 | 8 | // this will print MY_INT 9 | serialize_word(MY_INT); 10 | 11 | return (); 12 | } 13 | -------------------------------------------------------------------------------- /cairo_programs/proof_programs/abs_value.cairo: -------------------------------------------------------------------------------- 1 | ../abs_value.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/assert_250_bit_element_array.cairo: -------------------------------------------------------------------------------- 1 | ../assert_250_bit_element_array.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/assert_le_felt.cairo: -------------------------------------------------------------------------------- 1 | ../assert_le_felt.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/assert_lt_felt.cairo: -------------------------------------------------------------------------------- 1 | ../assert_lt_felt.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/assert_nn.cairo: -------------------------------------------------------------------------------- 1 | ../assert_nn.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/assert_not_equal.cairo: -------------------------------------------------------------------------------- 1 | ../assert_not_equal.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/assert_not_zero.cairo: -------------------------------------------------------------------------------- 1 | ../assert_not_zero.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/big_struct.cairo: -------------------------------------------------------------------------------- 1 | ../big_struct.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/bitwise_builtin_test.cairo: -------------------------------------------------------------------------------- 1 | ../bitwise_builtin_test.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/bitwise_output.cairo: -------------------------------------------------------------------------------- 1 | ../bitwise_output.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/bitwise_recursion.cairo: -------------------------------------------------------------------------------- 1 | ../bitwise_recursion.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/call_function_assign_param_by_name.cairo: -------------------------------------------------------------------------------- 1 | ../call_function_assign_param_by_name.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/common_signature.cairo: -------------------------------------------------------------------------------- 1 | ../common_signature.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/dict.cairo: -------------------------------------------------------------------------------- 1 | ../dict.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/dict_squash.cairo: -------------------------------------------------------------------------------- 1 | ../dict_squash.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/dict_update.cairo: -------------------------------------------------------------------------------- 1 | ../dict_update.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/factorial.cairo: -------------------------------------------------------------------------------- 1 | ../factorial.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/fibonacci.cairo: -------------------------------------------------------------------------------- 1 | ../fibonacci.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/function_return.cairo: -------------------------------------------------------------------------------- 1 | ../function_return.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/function_return_if_print.cairo: -------------------------------------------------------------------------------- 1 | ../function_return_if_print.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/function_return_to_variable.cairo: -------------------------------------------------------------------------------- 1 | ../function_return_to_variable.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/if_and_prime.cairo: -------------------------------------------------------------------------------- 1 | ../if_and_prime.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/if_in_function.cairo: -------------------------------------------------------------------------------- 1 | ../if_in_function.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/if_list.cairo: -------------------------------------------------------------------------------- 1 | ../if_list.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/if_reloc_equal.cairo: -------------------------------------------------------------------------------- 1 | ../if_reloc_equal.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/is_quad_residue.cairo: -------------------------------------------------------------------------------- 1 | ../is_quad_residue.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/jmp.cairo: -------------------------------------------------------------------------------- 1 | ../jmp.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/jmp_if_condition.cairo: -------------------------------------------------------------------------------- 1 | ../jmp_if_condition.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/keccak_builtin.cairo: -------------------------------------------------------------------------------- 1 | ../keccak_builtin.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/math_cmp.cairo: -------------------------------------------------------------------------------- 1 | ../math_cmp.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/memcpy_test.cairo: -------------------------------------------------------------------------------- 1 | ../memcpy_test.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/memory_holes.cairo: -------------------------------------------------------------------------------- 1 | ../memory_holes.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/memset.cairo: -------------------------------------------------------------------------------- 1 | ../memset.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/multiplicative_inverse.cairo: -------------------------------------------------------------------------------- 1 | ../multiplicative_inverse.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/not_main.cairo: -------------------------------------------------------------------------------- 1 | ../not_main.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/packed_sha256.cairo: -------------------------------------------------------------------------------- 1 | ../packed_sha256.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/pedersen_and_bitwise_builtins.cairo: -------------------------------------------------------------------------------- 1 | ../pedersen_and_bitwise_builtins.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/pedersen_and_bitwise_builtins_with_alloc_locals.cairo: -------------------------------------------------------------------------------- 1 | ../pedersen_and_bitwise_builtins_with_alloc_locals.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/pedersen_test.cairo: -------------------------------------------------------------------------------- 1 | ../pedersen_test.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/pointers.cairo: -------------------------------------------------------------------------------- 1 | ../pointers.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/poseidon_builtin.cairo: -------------------------------------------------------------------------------- 1 | ../poseidon_builtin.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/poseidon_hash.cairo: -------------------------------------------------------------------------------- 1 | ../poseidon_hash.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/pow.cairo: -------------------------------------------------------------------------------- 1 | ../pow.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/print.cairo: -------------------------------------------------------------------------------- 1 | ../print.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/return.cairo: -------------------------------------------------------------------------------- 1 | ../return.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/reversed_register_instructions.cairo: -------------------------------------------------------------------------------- 1 | ../reversed_register_instructions.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/sha256.cairo: -------------------------------------------------------------------------------- 1 | ../sha256.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/signed_div_rem.cairo: -------------------------------------------------------------------------------- 1 | ../signed_div_rem.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/simple_print.cairo: -------------------------------------------------------------------------------- 1 | ../simple_print.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/split_felt.cairo: -------------------------------------------------------------------------------- 1 | ../split_felt.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/split_int.cairo: -------------------------------------------------------------------------------- 1 | ../split_int.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/sqrt.cairo: -------------------------------------------------------------------------------- 1 | ../sqrt.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/squash_dict.cairo: -------------------------------------------------------------------------------- 1 | ../squash_dict.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/struct.cairo: -------------------------------------------------------------------------------- 1 | ../struct.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/test_addition_if.cairo: -------------------------------------------------------------------------------- 1 | ../test_addition_if.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/test_reverse_if.cairo: -------------------------------------------------------------------------------- 1 | ../test_reverse_if.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/test_subtraction_if.cairo: -------------------------------------------------------------------------------- 1 | ../test_subtraction_if.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/uint384.cairo: -------------------------------------------------------------------------------- 1 | ../uint384.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/uint384_extension.cairo: -------------------------------------------------------------------------------- 1 | ../uint384_extension.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/unsafe_keccak.cairo: -------------------------------------------------------------------------------- 1 | ../unsafe_keccak.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/unsafe_keccak_finalize.cairo: -------------------------------------------------------------------------------- 1 | ../unsafe_keccak_finalize.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/unsigned_div_rem.cairo: -------------------------------------------------------------------------------- 1 | ../unsigned_div_rem.cairo -------------------------------------------------------------------------------- /cairo_programs/proof_programs/usort.cairo: -------------------------------------------------------------------------------- 1 | ../usort.cairo -------------------------------------------------------------------------------- /cairo_programs/return.cairo: -------------------------------------------------------------------------------- 1 | func a{}() -> (b: felt) { 2 | return (5,); 3 | } 4 | 5 | func main{}() { 6 | a(); 7 | if ([ap - 1] == 5) { 8 | a(); 9 | } 10 | 11 | if ([ap - 1] == 0) { 12 | [ap] = 1, ap++; 13 | [ap] = 1; 14 | } 15 | ret; 16 | } 17 | -------------------------------------------------------------------------------- /cairo_programs/reversed_register_instructions.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | func main{output_ptr: felt*}() { 6 | let x = 100; 7 | 8 | x = [ap], ap++; 9 | 10 | [ap - 1] * [ap - 1] = [ap], ap++; 11 | 12 | [ap - 1] * [ap - 2] = [ap], ap++; 13 | 14 | [ap - 2] * 23 = [ap], ap++; 15 | 16 | [ap - 4] * 45 = [ap], ap++; 17 | 18 | [ap - 3] + [ap - 2] = [ap], ap++; 19 | 20 | [ap - 1] + [ap - 2] = [ap], ap++; 21 | 22 | [ap - 1] + 67 = [ap], ap++; 23 | 24 | serialize_word([ap - 1]); 25 | 26 | ret; 27 | } 28 | -------------------------------------------------------------------------------- /cairo_programs/search_sorted_lower.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | from starkware.cairo.common.find_element import search_sorted_lower 3 | from starkware.cairo.common.alloc import alloc 4 | 5 | struct MyStruct { 6 | a: felt, 7 | b: felt, 8 | } 9 | 10 | func main{range_check_ptr}() -> () { 11 | // Create an array with MyStruct elements (1,2), (3,4), (5,6). 12 | alloc_locals; 13 | let (local array_ptr: MyStruct*) = alloc(); 14 | assert array_ptr[0] = MyStruct(a=1, b=2); 15 | assert array_ptr[1] = MyStruct(a=3, b=4); 16 | assert array_ptr[2] = MyStruct(a=5, b=6); 17 | let (smallest_ptr: MyStruct*) = search_sorted_lower( 18 | array_ptr=array_ptr, elm_size=2, n_elms=3, key=2 19 | ); 20 | assert smallest_ptr.a = 3; 21 | assert smallest_ptr.b = 4; 22 | return (); 23 | } 24 | -------------------------------------------------------------------------------- /cairo_programs/set_add.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.set import set_add 5 | 6 | struct MyStruct { 7 | a: felt, 8 | b: felt, 9 | } 10 | 11 | func main{range_check_ptr}() { 12 | alloc_locals; 13 | 14 | // An array containing two structs. 15 | let (local my_list: MyStruct*) = alloc(); 16 | assert my_list[0] = MyStruct(a=1, b=3); 17 | assert my_list[1] = MyStruct(a=5, b=7); 18 | 19 | // Suppose that we want to add the element 20 | // MyStruct(a=2, b=3) to my_list, but only if it is not already 21 | // present (for the purpose of the example the contents of the 22 | // array are known, but this doesn't have to be the case) 23 | let list_end: felt* = &my_list[2]; 24 | let (new_elm: MyStruct*) = alloc(); 25 | assert new_elm[0] = MyStruct(a=2, b=3); 26 | 27 | set_add{set_end_ptr=list_end}(set_ptr=my_list, elm_size=MyStruct.SIZE, elm_ptr=new_elm); 28 | assert my_list[2] = MyStruct(a=2, b=3); 29 | return (); 30 | } 31 | -------------------------------------------------------------------------------- /cairo_programs/signature.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.cairo_secp.signature import div_mod_n, get_point_from_x 4 | from starkware.cairo.common.cairo_secp.bigint import BigInt3 5 | 6 | func main{range_check_ptr: felt}() { 7 | let a: BigInt3 = BigInt3(100, 99, 98); 8 | let b: BigInt3 = BigInt3(10, 9, 8); 9 | let (res) = div_mod_n(a, b); 10 | assert res.d0 = 3413472211745629263979533; 11 | assert res.d1 = 17305268010345238170172332; 12 | assert res.d2 = 11991751872105858217578135; 13 | 14 | let x: BigInt3 = BigInt3(100, 99, 98); 15 | let v: felt = 10; 16 | let (point) = get_point_from_x(x, v); 17 | assert point.x.d0 = 100; 18 | assert point.x.d1 = 99; 19 | assert point.x.d2 = 98; 20 | assert point.y.d0 = 50471654703173585387369794; 21 | assert point.y.d1 = 68898944762041070370364387; 22 | assert point.y.d2 = 16932612780945290933872774; 23 | return (); 24 | } 25 | -------------------------------------------------------------------------------- /cairo_programs/signed_div_rem.cairo: -------------------------------------------------------------------------------- 1 | %builtins output range_check 2 | from starkware.cairo.common.math import signed_div_rem, assert_le 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | func signed_div_rem_man{range_check_ptr}(value, div, bound) -> (q: felt, r: felt) { 6 | let r = [range_check_ptr]; 7 | let biased_q = [range_check_ptr + 1]; // == q + bound. 8 | 9 | let range_check_ptr = range_check_ptr + 2; 10 | %{ 11 | from starkware.cairo.common.math_utils import as_int, assert_integer 12 | 13 | assert_integer(ids.div) 14 | assert 0 < ids.div <= PRIME // range_check_builtin.bound, \ 15 | f'div={hex(ids.div)} is out of the valid range.' 16 | 17 | assert_integer(ids.bound) 18 | assert ids.bound <= range_check_builtin.bound // 2, \ 19 | f'bound={hex(ids.bound)} is out of the valid range.' 20 | 21 | int_value = as_int(ids.value, PRIME) 22 | q, ids.r = divmod(int_value, ids.div) 23 | 24 | assert -ids.bound <= q < ids.bound, \ 25 | f'{int_value} / {ids.div} = {q} is out of the range [{-ids.bound}, {ids.bound}).' 26 | 27 | ids.biased_q = q + ids.bound 28 | %} 29 | let q = biased_q - bound; 30 | assert value = q * div + r; 31 | assert_le(r, div - 1); 32 | assert_le(biased_q, 2 * bound - 1); 33 | return (q, r); 34 | } 35 | 36 | func main{output_ptr: felt*, range_check_ptr: felt}() { 37 | let (q_negative_expected, r_negative_expected) = signed_div_rem(-10, 3, 29); 38 | let (q_negative, r_negative) = signed_div_rem_man(-10, 3, 29); 39 | assert q_negative_expected = q_negative; 40 | assert r_negative_expected = r_negative; 41 | serialize_word(q_negative_expected); 42 | serialize_word(q_negative); 43 | serialize_word(r_negative_expected); 44 | serialize_word(r_negative); 45 | 46 | let (q_expected, r_expected) = signed_div_rem(10, 3, 29); 47 | let (q, r) = signed_div_rem_man(10, 3, 29); 48 | assert q_expected = q; 49 | assert r_expected = r; 50 | return (); 51 | } 52 | -------------------------------------------------------------------------------- /cairo_programs/simple_print.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.serialize import serialize_word 4 | 5 | func main{output_ptr: felt*}() { 6 | let x = 100; 7 | 8 | let y = x / 2; 9 | 10 | serialize_word(y); 11 | 12 | ret; 13 | } 14 | -------------------------------------------------------------------------------- /cairo_programs/split_felt.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math import assert_le 4 | from starkware.cairo.common.math import split_felt 5 | 6 | func split_felt_manual_implemetation{range_check_ptr}(value) -> (high: felt, low: felt) { 7 | // Note: the following code works because PRIME - 1 is divisible by 2**128. 8 | const MAX_HIGH = (-1) / 2 ** 128; 9 | const MAX_LOW = 0; 10 | 11 | // Guess the low and high parts of the integer. 12 | let low = [range_check_ptr]; 13 | let high = [range_check_ptr + 1]; 14 | let range_check_ptr = range_check_ptr + 2; 15 | 16 | %{ 17 | from starkware.cairo.common.math_utils import assert_integer 18 | assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128 19 | assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW 20 | assert_integer(ids.value) 21 | ids.low = ids.value & ((1 << 128) - 1) 22 | ids.high = ids.value >> 128 23 | %} 24 | 25 | assert value = high * (2 ** 128) + low; 26 | if (high == MAX_HIGH) { 27 | assert_le(low, MAX_LOW); 28 | } else { 29 | assert_le(high, MAX_HIGH - 1); 30 | } 31 | return (high=high, low=low); 32 | } 33 | 34 | func main{range_check_ptr: felt}() { 35 | let (m, n) = split_felt_manual_implemetation(5784800237655953878877368326340059594760); 36 | assert m = 17; 37 | assert n = 8; 38 | let (x, y) = split_felt(5784800237655953878877368326340059594760); 39 | assert x = 17; 40 | assert y = 8; 41 | return (); 42 | } 43 | -------------------------------------------------------------------------------- /cairo_programs/split_int.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math import split_int 4 | from starkware.cairo.common.alloc import alloc 5 | 6 | func main{range_check_ptr: felt}() { 7 | alloc_locals; 8 | let value = 456; 9 | let n = 3; 10 | let base = 10; 11 | let bound = 1000; 12 | let output: felt* = alloc(); 13 | split_int(value, n, base, bound, output); 14 | assert output[0] = 6; 15 | assert output[1] = 5; 16 | assert output[2] = 4; 17 | return (); 18 | } 19 | -------------------------------------------------------------------------------- /cairo_programs/sqrt.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.math import sqrt 4 | 5 | func main{range_check_ptr: felt}() { 6 | let result_a = sqrt(0); 7 | assert result_a = 0; 8 | 9 | let result_b = sqrt(2402); 10 | assert result_b = 49; 11 | 12 | let result_c = sqrt(361850278866613121369732278309507010562); 13 | assert result_c = 19022362599493605525; 14 | 15 | return (); 16 | } 17 | -------------------------------------------------------------------------------- /cairo_programs/squash_dict.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | 3 | from starkware.cairo.common.squash_dict import squash_dict 4 | from starkware.cairo.common.alloc import alloc 5 | from starkware.cairo.common.dict_access import DictAccess 6 | 7 | func main{range_check_ptr}() -> () { 8 | alloc_locals; 9 | let (dict_start: DictAccess*) = alloc(); 10 | assert dict_start[0] = DictAccess(key=0, prev_value=100, new_value=100); 11 | assert dict_start[1] = DictAccess(key=1, prev_value=50, new_value=50); 12 | assert dict_start[2] = DictAccess(key=0, prev_value=100, new_value=200); 13 | assert dict_start[3] = DictAccess(key=1, prev_value=50, new_value=100); 14 | assert dict_start[4] = DictAccess(key=0, prev_value=200, new_value=300); 15 | assert dict_start[5] = DictAccess(key=1, prev_value=100, new_value=150); 16 | 17 | let dict_end = dict_start + 6 * DictAccess.SIZE; 18 | // (dict_start, dict_end) now represents the dictionary 19 | // {0: 100, 1: 50, 0: 200, 1: 100, 0: 300, 1: 150}. 20 | 21 | // Squash the dictionary from an array of 6 DictAccess structs 22 | // to an array of 2, with a single DictAccess entry per key. 23 | let (local squashed_dict_start: DictAccess*) = alloc(); 24 | let (squashed_dict_end) = squash_dict{range_check_ptr=range_check_ptr}( 25 | dict_start, dict_end, squashed_dict_start 26 | ); 27 | 28 | // Check the values of the squashed_dict 29 | // should be: {0: (100, 300), 1: (50, 150)} 30 | assert squashed_dict_start[0] = DictAccess(key=0, prev_value=100, new_value=300); 31 | assert squashed_dict_start[1] = DictAccess(key=1, prev_value=50, new_value=150); 32 | return (); 33 | } 34 | -------------------------------------------------------------------------------- /cairo_programs/struct.cairo: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | first_member: felt, 3 | second_member: felt, 4 | } 5 | 6 | func main() { 7 | let struct_instance = MyStruct(first_member=1, second_member=2); 8 | let struct_instance_2 = MyStruct(3, 4); 9 | return (); 10 | } 11 | -------------------------------------------------------------------------------- /cairo_programs/test_addition_if.cairo: -------------------------------------------------------------------------------- 1 | func main{}() { 2 | [ap] = 3, ap++; 3 | 4 | if ([ap - 1] + 50 == 3) { 5 | [ap] = 25, ap++; 6 | [ap] = 10, ap++; 7 | [ap] = [ap - 1], ap++; 8 | [ap] = [ap - 1], ap++; 9 | } else { 10 | [ap] = 2, ap++; 11 | } 12 | [ap] = [ap - 1]; 13 | ret; 14 | } 15 | -------------------------------------------------------------------------------- /cairo_programs/test_reverse_if.cairo: -------------------------------------------------------------------------------- 1 | func main{}() { 2 | [ap] = 3, ap++; 3 | 4 | if (50 - [ap - 1] == 3) { 5 | [ap] = 25, ap++; 6 | [ap] = 10, ap++; 7 | [ap] = [ap - 1], ap++; 8 | [ap] = [ap - 1], ap++; 9 | } else { 10 | [ap] = 2, ap++; 11 | } 12 | [ap] = [ap - 1]; 13 | ret; 14 | } 15 | -------------------------------------------------------------------------------- /cairo_programs/test_subtraction_if.cairo: -------------------------------------------------------------------------------- 1 | func main{}() { 2 | [ap] = 3, ap++; 3 | 4 | if ([ap - 1] - 50 == 3) { 5 | [ap] = 25, ap++; 6 | [ap] = 10, ap++; 7 | [ap] = [ap - 1], ap++; 8 | [ap] = [ap - 1], ap++; 9 | } else { 10 | [ap] = 2, ap++; 11 | } 12 | [ap] = [ap - 1]; 13 | ret; 14 | } 15 | -------------------------------------------------------------------------------- /cairo_programs/uint256_root.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check bitwise 2 | from starkware.cairo.common.uint256 import ( 3 | Uint256, 4 | uint256_sqrt, 5 | ) 6 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin 7 | 8 | func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { 9 | let n = Uint256(0, 157560248172239344387757911110183813120); 10 | let res = uint256_sqrt(n); 11 | return (); 12 | } 13 | -------------------------------------------------------------------------------- /cairo_programs/unsafe_keccak.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.serialize import serialize_word 5 | from starkware.cairo.common.keccak import unsafe_keccak 6 | 7 | func main{output_ptr: felt*}() { 8 | alloc_locals; 9 | 10 | let (data: felt*) = alloc(); 11 | 12 | assert data[0] = 500; 13 | assert data[1] = 2; 14 | assert data[2] = 3; 15 | assert data[3] = 6; 16 | assert data[4] = 1; 17 | assert data[5] = 4444; 18 | 19 | let (low: felt, high: felt) = unsafe_keccak(data, 6); 20 | 21 | assert low = 182565855334575837944615807286777833262; 22 | assert high = 90044356407795786957420814893241941221; 23 | 24 | serialize_word(low); 25 | serialize_word(high); 26 | 27 | return (); 28 | } 29 | -------------------------------------------------------------------------------- /cairo_programs/unsafe_keccak_finalize.cairo: -------------------------------------------------------------------------------- 1 | %builtins output 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.serialize import serialize_word 5 | from starkware.cairo.common.keccak import unsafe_keccak_finalize, KeccakState 6 | from starkware.cairo.common.uint256 import Uint256 7 | 8 | func main{output_ptr: felt*}() { 9 | alloc_locals; 10 | 11 | let (data: felt*) = alloc(); 12 | 13 | assert data[0] = 0; 14 | assert data[1] = 1; 15 | assert data[2] = 2; 16 | 17 | let keccak_state = KeccakState(start_ptr=data, end_ptr=data + 2); 18 | 19 | let res: Uint256 = unsafe_keccak_finalize(keccak_state); 20 | 21 | assert res.low = 17219183504112405672555532996650339574; 22 | assert res.high = 235346966651632113557018504892503714354; 23 | 24 | serialize_word(res.low); 25 | serialize_word(res.high); 26 | 27 | return (); 28 | } 29 | -------------------------------------------------------------------------------- /cairo_programs/unsigned_div_rem.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | from starkware.cairo.common.math import unsigned_div_rem 3 | 4 | func unsigned_div_rem_man{range_check_ptr}(value, div) -> (q: felt, r: felt) { 5 | let r = [range_check_ptr]; 6 | let q = [range_check_ptr + 1]; 7 | let range_check_ptr = range_check_ptr + 2; 8 | %{ 9 | from starkware.cairo.common.math_utils import assert_integer 10 | assert_integer(ids.div) 11 | assert 0 < ids.div <= PRIME // range_check_builtin.bound, \ 12 | f'div={hex(ids.div)} is out of the valid range.' 13 | ids.q, ids.r = divmod(ids.value, ids.div) 14 | %} 15 | 16 | return (q, r); 17 | } 18 | 19 | func main{range_check_ptr: felt}() { 20 | let (q, r) = unsigned_div_rem_man(10, 3); 21 | let (expected_q, expected_r) = unsigned_div_rem(10, 3); 22 | assert q = expected_q; 23 | assert r = expected_r; 24 | assert q = 3; 25 | assert r = 1; 26 | return (); 27 | } 28 | -------------------------------------------------------------------------------- /cairo_programs/usort.cairo: -------------------------------------------------------------------------------- 1 | %builtins range_check 2 | from starkware.cairo.common.usort import usort 3 | from starkware.cairo.common.alloc import alloc 4 | 5 | func main{range_check_ptr}() -> () { 6 | alloc_locals; 7 | let (input_array: felt*) = alloc(); 8 | assert input_array[0] = 2; 9 | assert input_array[1] = 1; 10 | assert input_array[2] = 0; 11 | 12 | let (output_len, output, multiplicities) = usort(input_len=3, input=input_array); 13 | 14 | assert output_len = 3; 15 | assert output[0] = 0; 16 | assert output[1] = 1; 17 | assert output[2] = 2; 18 | assert multiplicities[0] = 1; 19 | assert multiplicities[1] = 1; 20 | assert multiplicities[2] = 1; 21 | return (); 22 | } 23 | -------------------------------------------------------------------------------- /check_fmt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | files=$(gofmt -l pkg) 4 | if [[ $files ]]; then 5 | echo -e "Some files are not correctly formatted:\n${files}" 6 | exit 1 7 | else 8 | exit 0 9 | fi 10 | -------------------------------------------------------------------------------- /cmd/cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "strings" 7 | 8 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/cairo_run" 9 | "github.com/urfave/cli/v2" 10 | ) 11 | 12 | func handleCommands(ctx *cli.Context) error { 13 | programPath := ctx.Args().First() 14 | 15 | layout := ctx.String("layout") 16 | if layout == "" { 17 | layout = "plain" 18 | } 19 | 20 | proofMode := ctx.Bool("proof_mode") 21 | 22 | secureRun := !proofMode 23 | if ctx.Bool("secure_run") { 24 | secureRun = true 25 | } 26 | 27 | cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, ProofMode: proofMode, Layout: layout, SecureRun: secureRun} 28 | 29 | cairoRunner, err := cairo_run.CairoRun(programPath, cairoRunConfig) 30 | if err != nil { 31 | return err 32 | } 33 | 34 | traceFilePath := ctx.String("trace_file") 35 | if traceFilePath == "" { 36 | traceFilePath = strings.Replace(programPath, ".json", ".go.trace", 1) 37 | } 38 | traceFile, err := os.OpenFile(traceFilePath, os.O_RDWR|os.O_CREATE, 0644) 39 | defer traceFile.Close() 40 | 41 | memoryFilePath := ctx.String("memory_file") 42 | if memoryFilePath == "" { 43 | memoryFilePath = strings.Replace(programPath, ".json", ".go.memory", 1) 44 | } 45 | memoryFile, err := os.OpenFile(memoryFilePath, os.O_RDWR|os.O_CREATE, 0644) 46 | defer memoryFile.Close() 47 | 48 | cairo_run.WriteEncodedTrace(cairoRunner.Vm.RelocatedTrace, traceFile) 49 | cairo_run.WriteEncodedMemory(cairoRunner.Vm.RelocatedMemory, memoryFile) 50 | return nil 51 | } 52 | 53 | func main() { 54 | app := &cli.App{ 55 | Flags: []cli.Flag{ 56 | &cli.BoolFlag{ 57 | Name: "proof_mode", 58 | Aliases: []string{"p"}, 59 | Usage: "Run in proof mode", 60 | }, 61 | &cli.BoolFlag{ 62 | Name: "secure_run", 63 | Aliases: []string{"s"}, 64 | Usage: "Run security checks. Default: true unless proof_mode is true", 65 | }, 66 | &cli.StringFlag{ 67 | Name: "layout", 68 | Aliases: []string{"l"}, 69 | Usage: "Default: plain", 70 | }, 71 | &cli.StringFlag{ 72 | Name: "trace_file", 73 | Aliases: []string{"t"}, 74 | Usage: "--trace_file ", 75 | }, 76 | &cli.StringFlag{ 77 | Name: "memory_file", 78 | Aliases: []string{"m"}, 79 | Usage: "--memory_file ", 80 | }, 81 | }, 82 | Action: handleCommands, 83 | } 84 | 85 | if err := app.Run(os.Args); err != nil { 86 | log.Fatal(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /docs/layout.md: -------------------------------------------------------------------------------- 1 | # Project layout 2 | 3 | ## Go project layout 4 | 5 | - `cmd`: apps/executables. 6 | - `pkg`: public packages. 7 | - `internal`: internal packages. The compiler enforces that they can't be included by other modules. 8 | 9 | ## Cairo VM - Go layout 10 | 11 | To be completed when packages are added. 12 | -------------------------------------------------------------------------------- /docs/rust-integration.md: -------------------------------------------------------------------------------- 1 | # Lambdaworks wrapper 2 | 3 | For now, this is a mock containing only a "number" function that always return 42. It's a 4 | proof of concept of a go package that integrates with a rust library. 5 | 6 | ## Package structure 7 | 8 | These are the relevant files: 9 | 10 | ``` 11 | ./pkg/lambdaworks: go package wrapper so that other packages can call this 12 | │ one without worrying about FFI, C or rust. 13 | ├──lambdaworks.go: go wrapper library code. Casts C types to go types. 14 | └── lib: directory with the rust and C code. 15 | ├── lambdaworks.h: C headers representing the functions that will 16 | │ be exported to go. 17 | └── lambdaworks: Rust package. 18 | ├── Cargo.Toml: Rust package definition. 19 | └── src/lib.rs: rust library. 20 | ``` 21 | 22 | ## Compiling 23 | 24 | The rust package can be compiled by moving to the `lib/lambdaworks` directory and executing `cargo build --release`. This produces a `lib/lambdaworks/target/liblambdaworks.a` file that will be imported by the `lambdaworks.go` as a static library, as we can see in the comment over the `Number` function. 25 | 26 | In `Makefile` we can see that one of the steps is actually moving to the rust project, compiling, and then copying the archive file to the `lib` directory so it can be consumed by the go code. 27 | 28 | ## Next steps: 29 | 30 | The lambdaworks math and crypto rust dependencies are already included in the `Cargo.toml`, but they are not used. The first step would be to add a wrapper that manipulates the finite field type instead of a simple integer. 31 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lambdaclass/cairo-vm.go 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/pkg/errors v0.9.1 7 | golang.org/x/crypto v0.13.0 8 | ) 9 | 10 | require ( 11 | github.com/ebfe/keccak v0.0.0-20150115210727-5cc570678d1b 12 | github.com/urfave/cli/v2 v2.24.1 13 | ) 14 | 15 | require ( 16 | github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect 17 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 18 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect 19 | ) 20 | 21 | require ( 22 | github.com/ethereum/go-ethereum v1.12.1 // indirect 23 | github.com/miguelmota/go-solidity-sha3 v0.1.1 // indirect 24 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 25 | golang.org/x/sys v0.12.0 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= 2 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 3 | github.com/ebfe/keccak v0.0.0-20150115210727-5cc570678d1b h1:BMyjwV6Fal/Ffphi4dJfulSxMeDl0xFS2vs5QLr6rsI= 4 | github.com/ebfe/keccak v0.0.0-20150115210727-5cc570678d1b/go.mod h1:fnviDXB7GJWiSUI9thIXmk9QKM8Rhj1JV/LcMRzkiVA= 5 | github.com/ethereum/go-ethereum v1.12.1/go.mod h1:zKetLweqBR8ZS+1O9iJWI8DvmmD2NzD19apjEWDCsnw= 6 | github.com/miguelmota/go-solidity-sha3 v0.1.1/go.mod h1:sax1FvQF+f71j8W1uUHMZn8NxKyl5rYLks2nqj8RFEw= 7 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 8 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 9 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 10 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 11 | github.com/urfave/cli/v2 v2.24.1 h1:/QYYr7g0EhwXEML8jO+8OYt5trPnLHS0p3mrgExJ5NU= 12 | github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= 13 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= 14 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= 15 | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 16 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= 17 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 18 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 19 | -------------------------------------------------------------------------------- /pkg/builtins/output_test.go: -------------------------------------------------------------------------------- 1 | package builtins_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/lambdaclass/cairo-vm.go/pkg/builtins" 8 | "github.com/lambdaclass/cairo-vm.go/pkg/vm" 9 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 10 | ) 11 | 12 | func TestOutputDeduceMemoryCell(t *testing.T) { 13 | output := builtins.NewOutputBuiltinRunner() 14 | a, b := output.DeduceMemoryCell(memory.NewRelocatable(0, 0), memory.NewMemory()) 15 | if a != nil || b != nil { 16 | t.Errorf("DeduceMemoryCell should do nothing") 17 | } 18 | } 19 | 20 | func TestOutputInitializeSegments(t *testing.T) { 21 | mem_manager := memory.NewMemorySegmentManager() 22 | output := builtins.NewOutputBuiltinRunner() 23 | output.InitializeSegments(&mem_manager) 24 | 25 | if mem_manager.Memory.NumSegments() != 1 { 26 | t.Errorf("Wrong number of segments after InitializeSegments") 27 | } 28 | 29 | if !reflect.DeepEqual(output.Base(), memory.NewRelocatable(0, 0)) { 30 | t.Errorf("Wrong builtin base after InitializeSegments") 31 | } 32 | } 33 | 34 | func TestOutputInitialStackIncluded(t *testing.T) { 35 | output := builtins.NewOutputBuiltinRunner() 36 | output.Include(true) 37 | initial_stack := output.InitialStack() 38 | expected_stack := []memory.MaybeRelocatable{*memory.NewMaybeRelocatableRelocatable(output.Base())} 39 | if !reflect.DeepEqual(initial_stack, expected_stack) { 40 | t.Errorf("Wrong initial stack") 41 | } 42 | } 43 | 44 | func TestOutputInitialStackNotIncluded(t *testing.T) { 45 | output := builtins.NewOutputBuiltinRunner() 46 | if len(output.InitialStack()) != 0 { 47 | t.Errorf("Initial stack should be empty if not included") 48 | } 49 | } 50 | 51 | func TestOutputAddValidationRule(t *testing.T) { 52 | empty_mem := memory.NewMemory() 53 | mem := memory.NewMemory() 54 | output := builtins.NewOutputBuiltinRunner() 55 | output.AddValidationRule(mem) 56 | // Check that the memory is equal to a newly created one to check that 57 | // no validation rules were added 58 | if !reflect.DeepEqual(mem, empty_mem) { 59 | t.Errorf("AddValidationRule should do nothing") 60 | } 61 | } 62 | 63 | func TestGetAllocatedMemoryUnitsOutput(t *testing.T) { 64 | output := builtins.NewOutputBuiltinRunner() 65 | vm := vm.NewVirtualMachine() 66 | 67 | mem_units, err := output.GetAllocatedMemoryUnits(&vm.Segments, vm.CurrentStep) 68 | if err != nil { 69 | t.Error("test failed with error: ", err) 70 | } 71 | if mem_units != 0 { 72 | t.Errorf("expected memory units to be 5, got: %d", mem_units) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /pkg/builtins/pedersen_test.go: -------------------------------------------------------------------------------- 1 | package builtins_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/lambdaclass/cairo-vm.go/pkg/builtins" 8 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 9 | "github.com/lambdaclass/cairo-vm.go/pkg/vm" 10 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 11 | ) 12 | 13 | func TestPedersenDeduceMemoryCell(t *testing.T) { 14 | pedersen := builtins.NewPedersenBuiltinRunner(256) 15 | vmachine := vm.NewVirtualMachine() 16 | vmachine.BuiltinRunners = append(vmachine.BuiltinRunners, pedersen) 17 | // Insert input cells into memory 18 | vmachine.Segments.AddSegment() 19 | vmachine.Segments.Memory.Insert( 20 | memory.NewRelocatable(0, 3), 21 | memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(32)), 22 | ) 23 | vmachine.Segments.Memory.Insert( 24 | memory.NewRelocatable(0, 4), 25 | memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(72)), 26 | ) 27 | vmachine.Segments.Memory.Insert( 28 | memory.NewRelocatable(0, 5), 29 | memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(0)), 30 | ) 31 | 32 | addr := memory.NewRelocatable(0, 5) 33 | expected_last_output_cell := memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromHex("0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f")) 34 | 35 | // Deduce Memory Cell 36 | val, err := vmachine.DeduceMemoryCell(addr) 37 | if !reflect.DeepEqual(val, expected_last_output_cell) || err != nil { 38 | t.Errorf("Wrong values returned by DeduceMemoryCell: result %s, expected %s", val.ToString(), expected_last_output_cell.ToString()) 39 | } 40 | 41 | // Computing again the deduce memory cell for the same address, must return nil 42 | second_compute, err := vmachine.DeduceMemoryCell(addr) 43 | if second_compute != nil || err != nil { 44 | t.Errorf("Wrong values returned by DeduceMemoryCell: result %s, expected %v", second_compute.ToString(), nil) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /pkg/builtins/signature_test.go: -------------------------------------------------------------------------------- 1 | package builtins_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/lambdaclass/cairo-vm.go/pkg/builtins" 7 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 8 | ) 9 | 10 | func TestBaseSignature(t *testing.T) { 11 | check_range := builtins.NewSignatureBuiltinRunner(2048) 12 | if check_range.Base() != memory.NewRelocatable(0, 0) { 13 | t.Errorf("Wrong base value in %s builtin", check_range.Name()) 14 | } 15 | } 16 | 17 | func TestInitializeSegmentsForSignatureBuiltin(t *testing.T) { 18 | range_check_builtin := builtins.NewSignatureBuiltinRunner(2048) 19 | segment_manager := memory.NewMemorySegmentManager() 20 | range_check_builtin.InitializeSegments(&segment_manager) 21 | if range_check_builtin.Base() != memory.NewRelocatable(0, 0) { 22 | t.Errorf("Builtin %s base is not 0", range_check_builtin.Name()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/hints/bigint_hint.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | "errors" 5 | "math/big" 6 | 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 8 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 10 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 11 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 12 | ) 13 | 14 | /* 15 | Implements hint: 16 | %{ 17 | from starkware.cairo.common.cairo_secp.secp_utils import split 18 | 19 | segments.write_arg(ids.res.address_, split(value)) 20 | %} 21 | */ 22 | 23 | func NondetBigInt3(virtual_machine VirtualMachine, execScopes ExecutionScopes, idsData IdsManager) error { 24 | resRelloc, err := idsData.GetAddr("res", &virtual_machine) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | valueUncast, err := execScopes.Get("value") 30 | if err != nil { 31 | return err 32 | } 33 | value, ok := valueUncast.(big.Int) 34 | if !ok { 35 | return errors.New("Could not cast value into big int") 36 | } 37 | 38 | bigint3Split, err := Bigint3Split(value) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | arg := make([]memory.MaybeRelocatable, 0) 44 | 45 | for i := 0; i < 3; i++ { 46 | m := memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(&bigint3Split[i])) 47 | arg = append(arg, *m) 48 | } 49 | 50 | _, loadErr := virtual_machine.Segments.LoadData(resRelloc, &arg) 51 | if loadErr != nil { 52 | return loadErr 53 | } 54 | 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /pkg/hints/bigint_hint_test.go: -------------------------------------------------------------------------------- 1 | package hints_test 2 | 3 | import ( 4 | "math/big" 5 | "testing" 6 | 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 10 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 11 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 12 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 13 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 14 | ) 15 | 16 | func TestNonDetBigInt3Ok(t *testing.T) { 17 | vm := NewVirtualMachine() 18 | 19 | vm.Segments.AddSegment() 20 | vm.Segments.AddSegment() 21 | vm.Segments.AddSegment() 22 | 23 | vm.RunContext.Pc = NewRelocatable(0, 0) 24 | vm.RunContext.Ap = NewRelocatable(1, 6) 25 | vm.RunContext.Fp = NewRelocatable(1, 6) 26 | 27 | value, _ := new(big.Int).SetString("7737125245533626718119526477371252455336267181195264773712524553362", 10) 28 | execScopes := NewExecutionScopes() 29 | 30 | execScopes.AssignOrUpdateVariable("value", *value) 31 | 32 | idsManager := SetupIdsForTest( 33 | map[string][]*MaybeRelocatable{ 34 | "res": {nil}, 35 | }, 36 | vm, 37 | ) 38 | 39 | hintProcessor := CairoVmHintProcessor{} 40 | hintData := any(HintData{ 41 | Ids: idsManager, 42 | Code: NONDET_BIGINT3_V1, 43 | }) 44 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) 45 | if err != nil { 46 | t.Errorf("Non Det Big Int 3 hint test failed with error: %s", err) 47 | } else { 48 | valueInStruct0, err := idsManager.GetStructFieldFelt("res", 0, vm) 49 | expected0 := lambdaworks.FeltFromDecString("773712524553362") 50 | if err != nil { 51 | t.Errorf("error fetching from ids manager : %s", err) 52 | } 53 | if valueInStruct0 != expected0 { 54 | t.Errorf(" Incorrect field value %s, expected %s", valueInStruct0.ToBigInt().Text(10), expected0.ToBigInt().Text(10)) 55 | } 56 | 57 | valueInStruct1, err := idsManager.GetStructFieldFelt("res", 1, vm) 58 | expected1 := lambdaworks.FeltFromDecString("57408430697461422066401280") 59 | if err != nil { 60 | t.Errorf("error fetching from ids manager : %s", err) 61 | } 62 | if valueInStruct1 != expected1 { 63 | t.Errorf(" Incorrect field value %s, expected %s", valueInStruct1.ToBigInt().Text(10), expected1.ToBigInt().Text(10)) 64 | } 65 | 66 | valueInStruct2, err := idsManager.GetStructFieldFelt("res", 2, vm) 67 | expected2 := lambdaworks.FeltFromDecString("1292469707114105") 68 | if err != nil { 69 | t.Errorf("error fetching from ids manager : %s", err) 70 | } 71 | if valueInStruct2 != expected2 { 72 | t.Errorf(" Incorrect field value %s, expected %s", valueInStruct2.ToBigInt().Text(10), expected2.ToBigInt().Text(10)) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /pkg/hints/dict_manager/dict_manager.go: -------------------------------------------------------------------------------- 1 | package dict_manager 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | // Manages dictionaries in a Cairo program. 10 | // Uses the segment index to associate the corresponding go dict with the Cairo dict. 11 | type DictManager struct { 12 | trackers map[int]*DictTracker 13 | } 14 | 15 | func NewDictManager() DictManager { 16 | return DictManager{ 17 | trackers: make(map[int]*DictTracker), 18 | } 19 | } 20 | 21 | func (d *DictManager) NewDictionary(dict *map[MaybeRelocatable]MaybeRelocatable, vm *VirtualMachine) Relocatable { 22 | base := vm.Segments.AddSegment() 23 | newTracker := NewDictTrackerForDictionary(base, dict) 24 | d.trackers[base.SegmentIndex] = &newTracker 25 | return base 26 | } 27 | 28 | func (d *DictManager) NewDefaultDictionary(defaultValue *MaybeRelocatable, vm *VirtualMachine) Relocatable { 29 | base := vm.Segments.AddSegment() 30 | newTracker := NewDictTrackerForDefaultDictionary(base, defaultValue) 31 | d.trackers[base.SegmentIndex] = &newTracker 32 | return base 33 | } 34 | 35 | func (d *DictManager) GetTracker(dict_ptr Relocatable) (*DictTracker, error) { 36 | tracker, ok := d.trackers[dict_ptr.SegmentIndex] 37 | if !ok { 38 | return nil, errors.Errorf("Dict Error: No dict tracker found for segment %d", dict_ptr.SegmentIndex) 39 | } 40 | if tracker.CurrentPtr != dict_ptr { 41 | return nil, errors.Errorf("Dict Error: Wrong dict pointer supplied. Got %v, expected %v", dict_ptr, tracker.CurrentPtr) 42 | } 43 | return tracker, nil 44 | } 45 | 46 | // Tracks the go dict associated with a Cairo dict. 47 | type DictTracker struct { 48 | data Dictionary 49 | // Pointer to the first unused position in the dict segment. 50 | CurrentPtr Relocatable 51 | } 52 | 53 | func NewDictTrackerForDictionary(base Relocatable, dict *map[MaybeRelocatable]MaybeRelocatable) DictTracker { 54 | return DictTracker{ 55 | data: NewDictionary(dict), 56 | CurrentPtr: base, 57 | } 58 | } 59 | 60 | func NewDictTrackerForDefaultDictionary(base Relocatable, defaultValue *MaybeRelocatable) DictTracker { 61 | return DictTracker{ 62 | data: NewDefaultDictionary(defaultValue), 63 | CurrentPtr: base, 64 | } 65 | } 66 | 67 | func (d *DictTracker) CopyDictionary() map[MaybeRelocatable]MaybeRelocatable { 68 | return d.data.dict 69 | } 70 | 71 | func (d *DictTracker) GetValue(key *MaybeRelocatable) (*MaybeRelocatable, error) { 72 | val := d.data.Get(key) 73 | if val == nil { 74 | return nil, errors.Errorf("Dict Error: No value found for key: %v", key) 75 | } 76 | return val, nil 77 | } 78 | 79 | func (d *DictTracker) InsertValue(key *MaybeRelocatable, val *MaybeRelocatable) { 80 | d.data.Insert(key, val) 81 | } 82 | 83 | type Dictionary struct { 84 | dict map[MaybeRelocatable]MaybeRelocatable 85 | defaultValue *MaybeRelocatable 86 | } 87 | 88 | func NewDefaultDictionary(defaultValue *MaybeRelocatable) Dictionary { 89 | return Dictionary{ 90 | dict: make(map[MaybeRelocatable]MaybeRelocatable), 91 | defaultValue: defaultValue, 92 | } 93 | } 94 | 95 | func NewDictionary(dict *map[MaybeRelocatable]MaybeRelocatable) Dictionary { 96 | return Dictionary{ 97 | dict: *dict, 98 | defaultValue: nil, 99 | } 100 | } 101 | 102 | func (d *Dictionary) Get(key *MaybeRelocatable) *MaybeRelocatable { 103 | val, ok := d.dict[*key] 104 | if ok { 105 | return &val 106 | } 107 | if d.defaultValue != nil { 108 | d.dict[*key] = *d.defaultValue 109 | } 110 | return d.defaultValue 111 | } 112 | 113 | func (d *Dictionary) Insert(key *MaybeRelocatable, val *MaybeRelocatable) { 114 | d.dict[*key] = *val 115 | } 116 | -------------------------------------------------------------------------------- /pkg/hints/field_utils.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | "errors" 5 | "math/big" 6 | 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 8 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 9 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 10 | 11 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 12 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 13 | ) 14 | 15 | /* 16 | Implements hint: 17 | %{ 18 | from starkware.cairo.common.cairo_secp.secp_utils import pack 19 | 20 | q, r = divmod(pack(ids.val, PRIME), SECP_P) 21 | assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." 22 | ids.q = q % PRIME 23 | %} 24 | */ 25 | 26 | func verifyZeroWithExternalConst(vm VirtualMachine, execScopes ExecutionScopes, idsData IdsManager) error { 27 | secpPuncast, err := execScopes.Get("SECP_P") 28 | if err != nil { 29 | return err 30 | } 31 | secpP, ok := secpPuncast.(big.Int) 32 | if !ok { 33 | return errors.New("Could not cast secpP into big int") 34 | } 35 | 36 | addr, err := idsData.GetAddr("val", &vm) 37 | if err != nil { 38 | return err 39 | } 40 | 41 | val, err := BigInt3FromBaseAddr(addr, "val", &vm) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | v := val.Pack86() 47 | q, r := v.DivMod(&v, &secpP, new(big.Int)) 48 | 49 | if r.Cmp(big.NewInt(0)) != 0 { 50 | return errors.New("verify remainder is not zero: Invalid input") 51 | } 52 | 53 | quotient := memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(q)) 54 | return idsData.Insert("q", quotient, &vm) 55 | } 56 | -------------------------------------------------------------------------------- /pkg/hints/field_utils_test.go: -------------------------------------------------------------------------------- 1 | package hints_test 2 | 3 | import ( 4 | "math/big" 5 | "testing" 6 | 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 10 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 11 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 12 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 13 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 14 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 15 | ) 16 | 17 | func TestVerifyZeroWithExternalConst(t *testing.T) { 18 | vm := NewVirtualMachine() 19 | vm.Segments.AddSegment() 20 | vm.Segments.AddSegment() 21 | 22 | vm.RunContext.Pc = NewRelocatable(0, 0) 23 | vm.RunContext.Ap = NewRelocatable(1, 9) 24 | vm.RunContext.Fp = NewRelocatable(1, 9) 25 | 26 | idsManager := SetupIdsForTest( 27 | map[string][]*MaybeRelocatable{ 28 | "val": {NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(55)), NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(0)), NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(0))}, 29 | "q": {nil}, 30 | }, 31 | vm, 32 | ) 33 | 34 | newScepP := big.NewInt(55) 35 | execScopes := NewExecutionScopes() 36 | 37 | execScopes.AssignOrUpdateVariable("SECP_P", *newScepP) 38 | 39 | hintProcessor := CairoVmHintProcessor{} 40 | hintData := any(HintData{ 41 | Ids: idsManager, 42 | Code: VERIFY_ZERO_EXTERNAL_SECP, 43 | }) 44 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) 45 | if err != nil { 46 | t.Errorf("verifyZeroWithExternalConst hint test failed with error: %s", err) 47 | } else { 48 | valueInMemory, err := idsManager.GetFelt("q", vm) 49 | if err != nil { 50 | t.Errorf("could not fetch value with error: %s", err) 51 | } 52 | if valueInMemory != FeltFromUint64(1) { 53 | t.Errorf("value in memory is not the expected") 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/blake2s_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const BLAKE2S_COMPUTE = `from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func 4 | compute_blake2s_func(segments=segments, output_ptr=ids.output)` 5 | 6 | const BLAKE2S_ADD_UINT256 = `B = 32 7 | MASK = 2 ** 32 - 1 8 | segments.write_arg(ids.data, [(ids.low >> (B * i)) & MASK for i in range(4)]) 9 | segments.write_arg(ids.data + 4, [(ids.high >> (B * i)) & MASK for i in range(4)])` 10 | 11 | const BLAKE2S_ADD_UINT256_BIGEND = `B = 32 12 | MASK = 2 ** 32 - 1 13 | segments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)]) 14 | segments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])` 15 | 16 | const BLAKE2S_FINALIZE = `# Add dummy pairs of input and output. 17 | from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress 18 | 19 | _n_packed_instances = int(ids.N_PACKED_INSTANCES) 20 | assert 0 <= _n_packed_instances < 20 21 | _blake2s_input_chunk_size_felts = int(ids.INPUT_BLOCK_FELTS) 22 | assert 0 <= _blake2s_input_chunk_size_felts < 100 23 | 24 | message = [0] * _blake2s_input_chunk_size_felts 25 | modified_iv = [IV[0] ^ 0x01010020] + IV[1:] 26 | output = blake2s_compress( 27 | message=message, 28 | h=modified_iv, 29 | t0=0, 30 | t1=0, 31 | f0=0xffffffff, 32 | f1=0, 33 | ) 34 | padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1) 35 | segments.write_arg(ids.blake2s_ptr_end, padding)` 36 | 37 | const BLAKE2S_FINALIZE_V2 = `# Add dummy pairs of input and output. 38 | from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress 39 | 40 | _n_packed_instances = int(ids.N_PACKED_INSTANCES) 41 | assert 0 <= _n_packed_instances < 20 42 | _blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS) 43 | assert 0 <= _blake2s_input_chunk_size_felts < 100 44 | 45 | message = [0] * _blake2s_input_chunk_size_felts 46 | modified_iv = [IV[0] ^ 0x01010020] + IV[1:] 47 | output = blake2s_compress( 48 | message=message, 49 | h=modified_iv, 50 | t0=0, 51 | t1=0, 52 | f0=0xffffffff, 53 | f1=0, 54 | ) 55 | padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1) 56 | segments.write_arg(ids.blake2s_ptr_end, padding)` 57 | 58 | const BLAKE2S_FINALIZE_V3 = `# Add dummy pairs of input and output. 59 | from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress 60 | 61 | _n_packed_instances = int(ids.N_PACKED_INSTANCES) 62 | assert 0 <= _n_packed_instances < 20 63 | _blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS) 64 | assert 0 <= _blake2s_input_chunk_size_felts < 100 65 | 66 | message = [0] * _blake2s_input_chunk_size_felts 67 | modified_iv = [IV[0] ^ 0x01010020] + IV[1:] 68 | output = blake2s_compress( 69 | message=message, 70 | h=modified_iv, 71 | t0=0, 72 | t1=0, 73 | f0=0xffffffff, 74 | f1=0, 75 | ) 76 | padding = (message + modified_iv + [0, 0xffffffff] + output) * (_n_packed_instances - 1) 77 | segments.write_arg(ids.blake2s_ptr_end, padding)` 78 | 79 | const EXAMPLE_BLAKE2S_COMPRESS = `from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress 80 | 81 | _blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS) 82 | assert 0 <= _blake2s_input_chunk_size_felts < 100 83 | 84 | new_state = blake2s_compress( 85 | message=memory.get_range(ids.blake2s_start, _blake2s_input_chunk_size_felts), 86 | h=[IV[0] ^ 0x01010020] + IV[1:], 87 | t0=ids.n_bytes, 88 | t1=0, 89 | f0=0xffffffff, 90 | f1=0, 91 | ) 92 | 93 | segments.write_arg(ids.output, new_state)` 94 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/dict_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const DEFAULT_DICT_NEW = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)" 4 | 5 | const DICT_READ = "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)\ndict_tracker.current_ptr += ids.DictAccess.SIZE\nids.value = dict_tracker.data[ids.key]" 6 | 7 | const DICT_WRITE = "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)\ndict_tracker.current_ptr += ids.DictAccess.SIZE\nids.dict_ptr.prev_value = dict_tracker.data[ids.key]\ndict_tracker.data[ids.key] = ids.new_value" 8 | 9 | const DICT_UPDATE = "# Verify dict pointer and prev value.\ndict_tracker = __dict_manager.get_tracker(ids.dict_ptr)\ncurrent_value = dict_tracker.data[ids.key]\nassert current_value == ids.prev_value, \\\n f'Wrong previous value in dict. Got {ids.prev_value}, expected {current_value}.'\n\n# Update value.\ndict_tracker.data[ids.key] = ids.new_value\ndict_tracker.current_ptr += ids.DictAccess.SIZE" 10 | 11 | const SQUASH_DICT = "dict_access_size = ids.DictAccess.SIZE\naddress = ids.dict_accesses.address_\nassert ids.ptr_diff % dict_access_size == 0, \\\n 'Accesses array size must be divisible by DictAccess.SIZE'\nn_accesses = ids.n_accesses\nif '__squash_dict_max_size' in globals():\n assert n_accesses <= __squash_dict_max_size, \\\n f'squash_dict() can only be used with n_accesses<={__squash_dict_max_size}. ' \\\n f'Got: n_accesses={n_accesses}.'\n# A map from key to the list of indices accessing it.\naccess_indices = {}\nfor i in range(n_accesses):\n key = memory[address + dict_access_size * i]\n access_indices.setdefault(key, []).append(i)\n# Descending list of keys.\nkeys = sorted(access_indices.keys(), reverse=True)\n# Are the keys used bigger than range_check bound.\nids.big_keys = 1 if keys[0] >= range_check_builtin.bound else 0\nids.first_key = key = keys.pop()" 12 | 13 | const SQUASH_DICT_INNER_SKIP_LOOP = "ids.should_skip_loop = 0 if current_access_indices else 1" 14 | 15 | const SQUASH_DICT_INNER_FIRST_ITERATION = "current_access_indices = sorted(access_indices[key])[::-1]\ncurrent_access_index = current_access_indices.pop()\nmemory[ids.range_check_ptr] = current_access_index" 16 | 17 | const SQUASH_DICT_INNER_CHECK_ACCESS_INDEX = "new_access_index = current_access_indices.pop()\nids.loop_temps.index_delta_minus1 = new_access_index - current_access_index - 1\ncurrent_access_index = new_access_index" 18 | 19 | const SQUASH_DICT_INNER_CONTINUE_LOOP = "ids.loop_temps.should_continue = 1 if current_access_indices else 0" 20 | 21 | const SQUASH_DICT_INNER_ASSERT_LEN_KEYS = "assert len(keys) == 0" 22 | 23 | const SQUASH_DICT_INNER_LEN_ASSERT = "assert len(current_access_indices) == 0" 24 | 25 | const SQUASH_DICT_INNER_USED_ACCESSES_ASSERT = "assert ids.n_used_accesses == len(access_indices[key])" 26 | 27 | const SQUASH_DICT_INNER_NEXT_KEY = "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'\nids.next_key = key = keys.pop()" 28 | 29 | const DICT_SQUASH_COPY_DICT = "# Prepare arguments for dict_new. In particular, the same dictionary values should be copied\n# to the new (squashed) dictionary.\nvm_enter_scope({\n # Make __dict_manager accessible.\n '__dict_manager': __dict_manager,\n # Create a copy of the dict, in case it changes in the future.\n 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),\n})" 30 | 31 | const DICT_SQUASH_UPDATE_PTR = "# Update the DictTracker's current_ptr to point to the end of the squashed dict.\n__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\\n ids.squashed_dict_end.address_" 32 | 33 | const DICT_NEW = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_dict(segments, initial_dict)\ndel initial_dict" 34 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/find_element_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const FIND_ELEMENT = `array_ptr = ids.array_ptr 4 | elm_size = ids.elm_size 5 | assert isinstance(elm_size, int) and elm_size > 0, \ 6 | f'Invalid value for elm_size. Got: {elm_size}.' 7 | key = ids.key 8 | 9 | if '__find_element_index' in globals(): 10 | ids.index = __find_element_index 11 | found_key = memory[array_ptr + elm_size * __find_element_index] 12 | assert found_key == key, \ 13 | f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \ 14 | f'expected key {key}, found key: {found_key}.' 15 | # Delete __find_element_index to make sure it's not used for the next calls. 16 | del __find_element_index 17 | else: 18 | n_elms = ids.n_elms 19 | assert isinstance(n_elms, int) and n_elms >= 0, \ 20 | f'Invalid value for n_elms. Got: {n_elms}.' 21 | if '__find_element_max_size' in globals(): 22 | assert n_elms <= __find_element_max_size, \ 23 | f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \ 24 | f'Got: n_elms={n_elms}.' 25 | 26 | for i in range(n_elms): 27 | if memory[array_ptr + elm_size * i] == key: 28 | ids.index = i 29 | break 30 | else: 31 | raise ValueError(f'Key {key} was not found.')` 32 | 33 | const SEARCH_SORTED_LOWER = `array_ptr = ids.array_ptr 34 | elm_size = ids.elm_size 35 | assert isinstance(elm_size, int) and elm_size > 0, \ 36 | f'Invalid value for elm_size. Got: {elm_size}.' 37 | 38 | n_elms = ids.n_elms 39 | assert isinstance(n_elms, int) and n_elms >= 0, \ 40 | f'Invalid value for n_elms. Got: {n_elms}.' 41 | if '__find_element_max_size' in globals(): 42 | assert n_elms <= __find_element_max_size, \ 43 | f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \ 44 | f'Got: n_elms={n_elms}.' 45 | 46 | for i in range(n_elms): 47 | if memory[array_ptr + elm_size * i] >= ids.key: 48 | ids.index = i 49 | break 50 | else: 51 | ids.index = n_elms` 52 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/keccak_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const UNSAFE_KECCAK = "from eth_hash.auto import keccak\n\ndata, length = ids.data, ids.length\n\nif '__keccak_max_size' in globals():\n assert length <= __keccak_max_size, \\\n f'unsafe_keccak() can only be used with length<={__keccak_max_size}. ' \\\n f'Got: length={length}.'\n\nkeccak_input = bytearray()\nfor word_i, byte_i in enumerate(range(0, length, 16)):\n word = memory[data + word_i]\n n_bytes = min(16, length - byte_i)\n assert 0 <= word < 2 ** (8 * n_bytes)\n keccak_input += word.to_bytes(n_bytes, 'big')\n\nhashed = keccak(keccak_input)\nids.high = int.from_bytes(hashed[:16], 'big')\nids.low = int.from_bytes(hashed[16:32], 'big')" 4 | 5 | const UNSAFE_KECCAK_FINALIZE = "from eth_hash.auto import keccak\nkeccak_input = bytearray()\nn_elms = ids.keccak_state.end_ptr - ids.keccak_state.start_ptr\nfor word in memory.get_range(ids.keccak_state.start_ptr, n_elms):\n keccak_input += word.to_bytes(16, 'big')\nhashed = keccak(keccak_input)\nids.high = int.from_bytes(hashed[:16], 'big')\nids.low = int.from_bytes(hashed[16:32], 'big')" 6 | 7 | const COMPARE_BYTES_IN_WORD_NONDET = "memory[ap] = to_felt_or_relocatable(ids.n_bytes < ids.BYTES_IN_WORD)" 8 | 9 | const COMPARE_KECCAK_FULL_RATE_IN_BYTES_NONDET = "memory[ap] = to_felt_or_relocatable(ids.n_bytes >= ids.KECCAK_FULL_RATE_IN_BYTES)" 10 | 11 | const BLOCK_PERMUTATION = `from starkware.cairo.common.keccak_utils.keccak_utils import keccak_func 12 | _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) 13 | assert 0 <= _keccak_state_size_felts < 100 14 | 15 | output_values = keccak_func(memory.get_range( 16 | ids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts)) 17 | segments.write_arg(ids.keccak_ptr, output_values)` 18 | 19 | const CAIRO_KECCAK_FINALIZE_V1 = `# Add dummy pairs of input and output. 20 | _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) 21 | _block_size = int(ids.BLOCK_SIZE) 22 | assert 0 <= _keccak_state_size_felts < 100 23 | assert 0 <= _block_size < 10 24 | inp = [0] * _keccak_state_size_felts 25 | padding = (inp + keccak_func(inp)) * _block_size 26 | segments.write_arg(ids.keccak_ptr_end, padding)` 27 | 28 | const CAIRO_KECCAK_FINALIZE_V2 = `# Add dummy pairs of input and output. 29 | _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) 30 | _block_size = int(ids.BLOCK_SIZE) 31 | assert 0 <= _keccak_state_size_felts < 100 32 | assert 0 <= _block_size < 1000 33 | inp = [0] * _keccak_state_size_felts 34 | padding = (inp + keccak_func(inp)) * _block_size 35 | segments.write_arg(ids.keccak_ptr_end, padding)` 36 | 37 | const KECCAK_WRITE_ARGS = `segments.write_arg(ids.inputs, [ids.low % 2 ** 64, ids.low // 2 ** 64]) 38 | segments.write_arg(ids.inputs + 2, [ids.high % 2 ** 64, ids.high // 2 ** 64])` 39 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/math_cmp_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const IS_NN = "memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1" 4 | 5 | const IS_NN_OUT_OF_RANGE = "memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1" 6 | 7 | const IS_LE_FELT = "memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1" 8 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/memcpy_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const ADD_SEGMENT = "memory[ap] = segments.add()" 4 | const VM_EXIT_SCOPE = "vm_exit_scope()" 5 | const VM_ENTER_SCOPE = "vm_enter_scope()" 6 | const MEMCPY_ENTER_SCOPE = "vm_enter_scope({'n': ids.len})" 7 | const MEMCPY_CONTINUE_COPYING = "n -= 1\nids.continue_copying = 1 if n > 0 else 0" 8 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/pow_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const POW = "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1" 4 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/secp_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const IMPORT_SECP256R1_ALPHA = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA" 4 | 5 | const IMPORT_SECP256R1_N = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N" 6 | 7 | const IMPORT_SECP256R1_P = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P" 8 | 9 | const VERIFY_ZERO_EXTERNAL_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME" 10 | 11 | const REDUCE_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack 12 | 13 | value = pack(ids.x, PRIME) % SECP_P` 14 | 15 | const REDUCE_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import pack 16 | value = pack(ids.x, PRIME) % SECP_P` 17 | 18 | const REDUCE_ED25519 = `from starkware.cairo.common.cairo_secp.secp_utils import pack 19 | SECP_P=2**255-19 20 | 21 | value = pack(ids.x, PRIME) % SECP_P` 22 | 23 | const VERIFY_ZERO_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack 24 | 25 | q, r = divmod(pack(ids.val, PRIME), SECP_P) 26 | assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." 27 | ids.q = q % PRIME` 28 | 29 | const VERIFY_ZERO_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P 30 | q, r = divmod(pack(ids.val, PRIME), SECP_P) 31 | assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." 32 | ids.q = q % PRIME` 33 | 34 | const VERIFY_ZERO_V3 = `from starkware.cairo.common.cairo_secp.secp_utils import pack 35 | SECP_P = 2**255-19 36 | to_assert = pack(ids.val, PRIME) 37 | q, r = divmod(pack(ids.val, PRIME), SECP_P) 38 | assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." 39 | ids.q = q % PRIME` 40 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/set_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const SET_ADD = "assert ids.elm_size > 0\nassert ids.set_ptr <= ids.set_end_ptr\nelm_list = memory.get_range(ids.elm_ptr, ids.elm_size)\nfor i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size):\n if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list:\n ids.index = i // ids.elm_size\n ids.is_elm_in_set = 1\n break\nelse:\n ids.is_elm_in_set = 0" 4 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/sha256_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const SHA256_INPUT = "ids.full_word = int(ids.n_bytes >= 4)" 4 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/signature_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const DIV_MOD_N_PACKED_DIVMOD_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import N, pack 4 | from starkware.python.math_utils import div_mod, safe_div 5 | 6 | a = pack(ids.a, PRIME) 7 | b = pack(ids.b, PRIME) 8 | value = res = div_mod(a, b, N)` 9 | 10 | const DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N = `from starkware.cairo.common.cairo_secp.secp_utils import pack 11 | from starkware.python.math_utils import div_mod, safe_div 12 | 13 | a = pack(ids.a, PRIME) 14 | b = pack(ids.b, PRIME) 15 | value = res = div_mod(a, b, N)` 16 | 17 | const DIV_MOD_N_SAFE_DIV = "value = k = safe_div(res * b - a, N)" 18 | 19 | const DIV_MOD_N_SAFE_DIV_PLUS_ONE = "value = k_plus_one = safe_div(res * b - a, N) + 1" 20 | 21 | const XS_SAFE_DIV = "value = k = safe_div(res * s - x, N)" 22 | 23 | const GET_POINT_FROM_X = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack 24 | 25 | x_cube_int = pack(ids.x_cube, PRIME) % SECP_P 26 | y_square_int = (x_cube_int + ids.BETA) % SECP_P 27 | y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P) 28 | 29 | # We need to decide whether to take y or SECP_P - y. 30 | if ids.v % 2 == y % 2: 31 | value = y 32 | else: 33 | value = (-y) % SECP_P` 34 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/uint256_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const UINT256_ADD = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0\nsum_high = ids.a.high + ids.b.high + ids.carry_low\nids.carry_high = 1 if sum_high >= ids.SHIFT else 0" 4 | const UINT256_ADD_LOW = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0" 5 | const SPLIT_64 = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64" 6 | const UINT256_SQRT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root.low = root\nids.root.high = 0" 7 | const UINT256_SQRT_FELT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root = root;" 8 | const UINT256_SIGNED_NN = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" 9 | const UINT256_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" 10 | const UINT256_EXPANDED_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.b23 << 128) + ids.div.b01\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" 11 | const UINT256_MUL_DIV_MOD = "a = (ids.a.high << 128) + ids.a.low\nb = (ids.b.high << 128) + ids.b.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a * b, div)\n\nids.quotient_low.low = quotient & ((1 << 128) - 1)\nids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1)\nids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1)\nids.quotient_high.high = quotient >> 384\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" 12 | const UINT256_SUB = `def split(num: int, num_bits_shift: int = 128, length: int = 2): 13 | a = [] 14 | for _ in range(length): 15 | a.append( num & ((1 << num_bits_shift) - 1) ) 16 | num = num >> num_bits_shift 17 | return tuple(a) 18 | 19 | def pack(z, num_bits_shift: int = 128) -> int: 20 | limbs = (z.low, z.high) 21 | return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) 22 | 23 | a = pack(ids.a) 24 | b = pack(ids.b) 25 | res = (a - b)%2**256 26 | res_split = split(res) 27 | ids.res.low = res_split[0] 28 | ids.res.high = res_split[1]` 29 | -------------------------------------------------------------------------------- /pkg/hints/hint_codes/usort_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hint_codes 2 | 3 | const USORT_ENTER_SCOPE = "vm_enter_scope(dict(__usort_max_size = globals().get('__usort_max_size')))" 4 | 5 | const USORT_BODY = `from collections import defaultdict 6 | 7 | input_ptr = ids.input 8 | input_len = int(ids.input_len) 9 | if __usort_max_size is not None: 10 | assert input_len <= __usort_max_size, ( 11 | f"usort() can only be used with input_len<={__usort_max_size}. " 12 | f"Got: input_len={input_len}." 13 | ) 14 | 15 | positions_dict = defaultdict(list) 16 | for i in range(input_len): 17 | val = memory[input_ptr + i] 18 | positions_dict[val].append(i) 19 | 20 | output = sorted(positions_dict.keys()) 21 | ids.output_len = len(output) 22 | ids.output = segments.gen_arg(output) 23 | ids.multiplicities = segments.gen_arg([len(positions_dict[k]) for k in output])` 24 | 25 | const USORT_VERIFY = `last_pos = 0 26 | positions = positions_dict[ids.value][::-1]` 27 | 28 | const USORT_VERIFY_MULTIPLICITY_ASSERT = "assert len(positions) == 0" 29 | 30 | const USORT_VERIFY_MULTIPLICITY_BODY = `current_pos = positions.pop() 31 | ids.next_item_index = current_pos - last_pos 32 | last_pos = current_pos + 1` 33 | -------------------------------------------------------------------------------- /pkg/hints/hint_processor_test.go: -------------------------------------------------------------------------------- 1 | package hints_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 9 | "github.com/lambdaclass/cairo-vm.go/pkg/parser" 10 | "github.com/lambdaclass/cairo-vm.go/pkg/vm" 11 | ) 12 | 13 | func TestCompileHintEmpty(t *testing.T) { 14 | hintProcessor := &CairoVmHintProcessor{} 15 | hintParams := &parser.HintParams{} 16 | referenceManager := &parser.ReferenceManager{} 17 | expectedData := HintData{} 18 | data, err := hintProcessor.CompileHint(hintParams, referenceManager) 19 | if err != nil { 20 | t.Errorf("Error in test: %s", err) 21 | } 22 | if reflect.DeepEqual(data.(HintData), expectedData) { 23 | t.Errorf("Wrong hint data, %+v", data) 24 | } 25 | } 26 | 27 | func TestCompileHintHappyPath(t *testing.T) { 28 | hintProcessor := &CairoVmHintProcessor{} 29 | hintParams := &parser.HintParams{ 30 | Code: "ids.a = ids.b", 31 | FlowTrackingData: parser.FlowTrackingData{ 32 | APTracking: parser.ApTrackingData{Group: 1, Offset: 2}, 33 | ReferenceIds: map[string]uint{"__main.__.a": 0, "__main__.b": 1}, 34 | }, 35 | } 36 | referenceManager := &parser.ReferenceManager{ 37 | References: []parser.Reference{ 38 | { 39 | Value: "cast(ap + (-2), felt)", 40 | }, 41 | { 42 | Value: "cast(ap + (-1), felt)", 43 | }, 44 | }, 45 | } 46 | expectedData := HintData{ 47 | Ids: IdsManager{References: map[string]HintReference{ 48 | "a": { 49 | Offset1: OffsetValue{ 50 | ValueType: Reference, 51 | Value: -2, 52 | }, 53 | ValueType: "felt", 54 | }, 55 | "b": { 56 | Offset1: OffsetValue{ 57 | ValueType: Reference, 58 | Value: -1, 59 | }, 60 | ValueType: "felt", 61 | }, 62 | }, 63 | HintApTracking: parser.ApTrackingData{Group: 1, Offset: 2}, 64 | }, 65 | Code: "ids.a = ids.b", 66 | } 67 | data, err := hintProcessor.CompileHint(hintParams, referenceManager) 68 | if err != nil { 69 | t.Errorf("Error in test: %s", err) 70 | } 71 | if !reflect.DeepEqual(data.(HintData), expectedData) { 72 | t.Errorf("Wrong hint data, %+v", data) 73 | } 74 | } 75 | 76 | func TestCompileHintMissingReference(t *testing.T) { 77 | hintProcessor := &CairoVmHintProcessor{} 78 | hintParams := &parser.HintParams{ 79 | FlowTrackingData: parser.FlowTrackingData{ 80 | ReferenceIds: map[string]uint{"a": 0, "b": 1}, 81 | }, 82 | } 83 | referenceManager := &parser.ReferenceManager{} 84 | _, err := hintProcessor.CompileHint(hintParams, referenceManager) 85 | if err == nil { 86 | t.Errorf("Should have failed") 87 | } 88 | } 89 | 90 | func TestExecuteHintWrongHintData(t *testing.T) { 91 | hintProcessor := &CairoVmHintProcessor{} 92 | hintData := any("Mistake") 93 | vm := vm.NewVirtualMachine() 94 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 95 | if err == nil { 96 | t.Errorf("Should have failed") 97 | } 98 | } 99 | 100 | func TestExecuteHintUnknownHint(t *testing.T) { 101 | hintProcessor := &CairoVmHintProcessor{} 102 | hintData := any(HintData{Code: "print(Hello World)"}) 103 | vm := vm.NewVirtualMachine() 104 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 105 | if err == nil { 106 | t.Errorf("Should have failed") 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /pkg/hints/hint_utils/bigint_utils.go: -------------------------------------------------------------------------------- 1 | package hint_utils 2 | 3 | import ( 4 | "math/big" 5 | 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 9 | 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | // In cairo, various structs are used to represent big integers, all of them have numbered fields of Felt type (d0, d1,...) and share the same behaviours 14 | // This file contains an implementation of each behaviour at the limbs level, and the wrappers for each specific type 15 | 16 | // Generic methods for all types 17 | func limbsFromVarName(nLimbs int, name string, ids IdsManager, vm *VirtualMachine) ([]Felt, error) { 18 | baseAddr, err := ids.GetAddr(name, vm) 19 | if err != nil { 20 | return nil, err 21 | } 22 | return limbsFromBaseAddress(nLimbs, name, baseAddr, vm) 23 | } 24 | 25 | func limbsFromBaseAddress(nLimbs int, name string, addr Relocatable, vm *VirtualMachine) ([]Felt, error) { 26 | limbs := make([]Felt, 0) 27 | for i := 0; i < nLimbs; i++ { 28 | felt, err := vm.Segments.Memory.GetFelt(addr.AddUint(uint(i))) 29 | if err == nil { 30 | limbs = append(limbs, felt) 31 | } else { 32 | return nil, errors.Errorf("Identifier %s has no member d%d", name, i) 33 | } 34 | } 35 | return limbs, nil 36 | } 37 | 38 | func limbsPack86(limbs []Felt) big.Int { 39 | sum := big.NewInt(0) 40 | for i := 0; i < 3; i++ { 41 | felt := limbs[i] 42 | shifed := new(big.Int).Lsh(felt.ToSigned(), uint(i*86)) 43 | sum.Add(sum, shifed) 44 | } 45 | return *sum 46 | } 47 | 48 | func limbsPack(limbs []Felt) big.Int { 49 | sum := big.NewInt(0) 50 | for i := 0; i < len(limbs); i++ { 51 | felt := limbs[i] 52 | shifed := new(big.Int).Lsh(felt.ToSigned(), uint(i*128)) 53 | sum.Add(sum, shifed) 54 | } 55 | return *sum 56 | } 57 | 58 | func limbsInsertFromVarName(limbs []Felt, name string, ids IdsManager, vm *VirtualMachine) error { 59 | baseAddr, err := ids.GetAddr(name, vm) 60 | if err != nil { 61 | return err 62 | } 63 | for i := 0; i < len(limbs); i++ { 64 | err = vm.Segments.Memory.Insert(baseAddr.AddUint(uint(i)), NewMaybeRelocatableFelt(limbs[i])) 65 | if err != nil { 66 | return err 67 | } 68 | } 69 | return nil 70 | } 71 | 72 | func splitIntoLimbs(num *big.Int, numLimbs int) []Felt { 73 | limbs := make([]Felt, 0, numLimbs) 74 | bitmask := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1)) 75 | for i := 0; i < numLimbs; i++ { 76 | limbs[i] = FeltFromBigInt(new(big.Int).Lsh(new(big.Int).And(num, bitmask), 128)) 77 | } 78 | return limbs 79 | } 80 | 81 | // Concrete type definitions 82 | 83 | // BigInt3 84 | 85 | type BigInt3 struct { 86 | Limbs []Felt 87 | } 88 | 89 | func (b *BigInt3) Pack86() big.Int { 90 | return limbsPack86(b.Limbs) 91 | } 92 | 93 | func BigInt3FromBaseAddr(addr Relocatable, name string, vm *VirtualMachine) (BigInt3, error) { 94 | limbs, err := limbsFromBaseAddress(3, name, addr, vm) 95 | return BigInt3{Limbs: limbs}, err 96 | } 97 | 98 | func BigInt3FromVarName(name string, ids IdsManager, vm *VirtualMachine) (BigInt3, error) { 99 | limbs, err := limbsFromVarName(3, name, ids, vm) 100 | return BigInt3{Limbs: limbs}, err 101 | } 102 | 103 | // Uint384 104 | 105 | type Uint384 = BigInt3 106 | 107 | func Uint384FromVarName(name string, ids IdsManager, vm *VirtualMachine) (Uint384, error) { 108 | return BigInt3FromVarName(name, ids, vm) 109 | } 110 | -------------------------------------------------------------------------------- /pkg/hints/hint_utils/blake2s_hash.go: -------------------------------------------------------------------------------- 1 | package hint_utils 2 | 3 | func IV() [8]uint32 { 4 | return [8]uint32{ 5 | 0x6A09E667, 6 | 0xBB67AE85, 7 | 0x3C6EF372, 8 | 0xA54FF53A, 9 | 0x510E527F, 10 | 0x9B05688C, 11 | 0x1F83D9AB, 12 | 0x5BE0CD19} 13 | } 14 | 15 | func SIGMA() [10][16]uint32 { 16 | return [10][16]uint32{ 17 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 18 | {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, 19 | {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, 20 | {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, 21 | {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, 22 | {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, 23 | {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, 24 | {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, 25 | {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, 26 | {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, 27 | } 28 | } 29 | 30 | func rightRot(value uint32, n uint32) uint32 { 31 | return (value >> n) | ((value & ((1 << n) - 1)) << (32 - n)) 32 | } 33 | 34 | func mix(a uint32, b uint32, c uint32, d uint32, m0 uint32, m1 uint32) (uint32, uint32, uint32, uint32) { 35 | a = a + b + m0 36 | d = rightRot(d^a, 16) 37 | c = c + d 38 | b = rightRot(b^c, 12) 39 | a = a + b + m1 40 | d = rightRot(d^a, 8) 41 | c = c + d 42 | b = rightRot(b^c, 7) 43 | return a, b, c, d 44 | } 45 | 46 | func blakeRound(state []uint32, message [16]uint32, sigma [16]uint32) []uint32 { 47 | state[0], state[4], state[8], state[12] = mix( 48 | state[0], 49 | state[4], 50 | state[8], 51 | state[12], 52 | message[sigma[0]], 53 | message[sigma[1]], 54 | ) 55 | state[1], state[5], state[9], state[13] = mix( 56 | state[1], 57 | state[5], 58 | state[9], 59 | state[13], 60 | message[sigma[2]], 61 | message[sigma[3]], 62 | ) 63 | state[2], state[6], state[10], state[14] = mix( 64 | state[2], 65 | state[6], 66 | state[10], 67 | state[14], 68 | message[sigma[4]], 69 | message[sigma[5]], 70 | ) 71 | state[3], state[7], state[11], state[15] = mix( 72 | state[3], 73 | state[7], 74 | state[11], 75 | state[15], 76 | message[sigma[6]], 77 | message[sigma[7]], 78 | ) 79 | state[0], state[5], state[10], state[15] = mix( 80 | state[0], 81 | state[5], 82 | state[10], 83 | state[15], 84 | message[sigma[8]], 85 | message[sigma[9]], 86 | ) 87 | state[1], state[6], state[11], state[12] = mix( 88 | state[1], 89 | state[6], 90 | state[11], 91 | state[12], 92 | message[sigma[10]], 93 | message[sigma[11]], 94 | ) 95 | state[2], state[7], state[8], state[13] = mix( 96 | state[2], 97 | state[7], 98 | state[8], 99 | state[13], 100 | message[sigma[12]], 101 | message[sigma[13]], 102 | ) 103 | state[3], state[4], state[9], state[14] = mix( 104 | state[3], 105 | state[4], 106 | state[9], 107 | state[14], 108 | message[sigma[14]], 109 | message[sigma[15]], 110 | ) 111 | return state 112 | } 113 | 114 | func Blake2sCompress(h [8]uint32, message [16]uint32, t0 uint32, t1 uint32, f0 uint32, f1 uint32) []uint32 { 115 | iv := IV() 116 | 117 | state := make([]uint32, 0, 16) 118 | 119 | state = append(state, h[:]...) 120 | state = append(state, iv[:4]...) 121 | state = append(state, iv[4]^t0, iv[5]^t1, iv[6]^f0, iv[7]^f1) 122 | 123 | for _, sigmaList := range SIGMA() { 124 | state = blakeRound(state, message, sigmaList) 125 | } 126 | 127 | newState := make([]uint32, 0, 8) 128 | for i := 0; i < 8; i++ { 129 | newState = append(newState, h[i]^state[i]^state[8+i]) 130 | } 131 | 132 | return newState 133 | } 134 | -------------------------------------------------------------------------------- /pkg/hints/hint_utils/secp_utils.go: -------------------------------------------------------------------------------- 1 | package hint_utils 2 | 3 | import ( 4 | "errors" 5 | "math/big" 6 | ) 7 | 8 | func SECP_P() big.Int { 9 | secpP, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10) 10 | return *secpP 11 | } 12 | 13 | func SECP_P_V2() big.Int { 14 | secpP, _ := new(big.Int).SetString("57896044618658097711785492504343953926634992332820282019728792003956564819949", 10) 15 | return *secpP 16 | } 17 | 18 | func ALPHA() big.Int { 19 | alpha := big.NewInt(0) 20 | return *alpha 21 | } 22 | 23 | func SECP256R1_ALPHA() big.Int { 24 | secpPalpha, _ := new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853948", 10) 25 | return *secpPalpha 26 | } 27 | 28 | func SECP256R1_N() big.Int { 29 | secp256, _ := new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10) 30 | return *secp256 31 | } 32 | 33 | func SECP256R1_P() big.Int { 34 | secp256r1, _ := new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10) 35 | return *secp256r1 36 | } 37 | 38 | func BASE_MINUS_ONE() *big.Int { 39 | res, _ := new(big.Int).SetString("77371252455336267181195263", 10) 40 | return res 41 | } 42 | 43 | func Bigint3Split(integer big.Int) ([]big.Int, error) { 44 | canonicalRepr := make([]big.Int, 3) 45 | num := integer 46 | 47 | for i := 0; i < 3; i++ { 48 | canonicalRepr[i] = *new(big.Int).And(&num, BASE_MINUS_ONE()) 49 | num = *new(big.Int).Rsh(&num, 86) 50 | } 51 | if num.Cmp(big.NewInt(0)) != 0 { 52 | return nil, errors.New("HintError SecpSplitOutOfRange") 53 | } 54 | 55 | return canonicalRepr, nil 56 | } 57 | -------------------------------------------------------------------------------- /pkg/hints/hint_utils/testing_utils.go: -------------------------------------------------------------------------------- 1 | package hint_utils 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 8 | "github.com/lambdaclass/cairo-vm.go/pkg/parser" 9 | "github.com/lambdaclass/cairo-vm.go/pkg/types" 10 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 11 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 12 | ) 13 | 14 | // Receives a map and builds a setup for hints tests containing ids 15 | // For usage examples refer to testing_utils_test.go 16 | // Builds the IdsManager & Inserts ids into memory 17 | // Works as follows: 18 | // Each map entry represents an ids variable 19 | // That identifier can represent one or more elements (aka be an elment or struct) 20 | // Some of these elements may also be missing (inserted during the hint), and are represented as a nil pointer 21 | // Considerations: 22 | // All references will be FP-based, so please don't update the value of FP after calling this function, 23 | // and make sure that the memory at fp's segment is clear from its current offset onwards 24 | func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachine) IdsManager { 25 | manager := NewIdsManager(make(map[string]HintReference), parser.ApTrackingData{}, []string{}) 26 | base_addr := vm.RunContext.Fp 27 | current_offset := 0 28 | for name, elems := range ids { 29 | // Create reference 30 | manager.References[name] = HintReference{ 31 | Dereference: true, 32 | Offset1: OffsetValue{ 33 | ValueType: Reference, 34 | Value: current_offset, 35 | Register: FP, 36 | }, 37 | } 38 | // Update current_offset 39 | current_offset += len(elems) 40 | 41 | // Insert ids variables (if present) 42 | for n, elem := range elems { 43 | if elem != nil { 44 | vm.Segments.Memory.Insert(base_addr.AddUint(uint(n)), elem) 45 | } 46 | } 47 | // Update base_addr 48 | base_addr.Offset += uint(len(elems)) 49 | } 50 | return manager 51 | } 52 | 53 | // Returns a constants map accoring to the new_constants map received 54 | // Adds a path to each constant and a matching path to the hint's accessible scopes 55 | func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids *IdsManager) map[string]lambdaworks.Felt { 56 | constants := make(map[string]lambdaworks.Felt) 57 | ids.AccessibleScopes = append(ids.AccessibleScopes, "path") 58 | for name, constant := range new_constants { 59 | constants["path."+name] = constant 60 | } 61 | return constants 62 | } 63 | 64 | func CheckScopeVar[T any](name string, expectedVal T, scopes *types.ExecutionScopes, t *testing.T) { 65 | val, err := types.FetchScopeVar[T](name, scopes) 66 | if err != nil { 67 | t.Error(err.Error()) 68 | } 69 | if !reflect.DeepEqual(val, expectedVal) { 70 | t.Errorf("Wrong scope var %s.\n Expected: %v, got: %v", name, expectedVal, val) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pkg/hints/hint_utils/uint256_utils.go: -------------------------------------------------------------------------------- 1 | package hint_utils 2 | 3 | import ( 4 | "math/big" 5 | 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 7 | ) 8 | 9 | type Uint256 struct { 10 | Low Felt 11 | High Felt 12 | } 13 | 14 | func (u *Uint256) ToString() string { 15 | return "Uint256 { low: " + u.Low.ToSignedFeltString() + ", high: " + u.High.ToSignedFeltString() + " }" 16 | } 17 | 18 | /* 19 | Returns a Uint256 as a big.Int 20 | 21 | res = high << 128 + low 22 | */ 23 | func (u *Uint256) ToBigInt() *big.Int { 24 | high := new(big.Int).Lsh(u.High.ToBigInt(), 128) 25 | low := u.Low.ToBigInt() 26 | res := new(big.Int).Add(high, low) 27 | return res 28 | } 29 | 30 | /* 31 | Returns a big.Int as Uint256 32 | */ 33 | func ToUint256(a *big.Int) Uint256 { 34 | maxU128, _ := new(big.Int).SetString("340282366920938463463374607431768211455", 10) 35 | low := new(big.Int).And(a, maxU128) 36 | high := new(big.Int).Rsh(a, 128) 37 | return Uint256{Low: FeltFromBigInt(low), High: FeltFromBigInt(high)} 38 | } 39 | 40 | func (u *Uint256) IsEqual(other Uint256) bool { 41 | return u.Low.Cmp(other.Low) == 0 && u.High.Cmp(other.High) == 0 42 | } 43 | -------------------------------------------------------------------------------- /pkg/hints/math_cmp_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | "github.com/lambdaclass/cairo-vm.go/pkg/builtins" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 9 | ) 10 | 11 | // memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1 12 | func isNN(ids IdsManager, vm *VirtualMachine) error { 13 | a, err := ids.GetFelt("a", vm) 14 | if err != nil { 15 | return err 16 | } 17 | if a.Bits() < builtins.RANGE_CHECK_N_PARTS*builtins.INNER_RC_BOUND_SHIFT { 18 | return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) 19 | } 20 | return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltOne())) 21 | } 22 | 23 | // memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1 24 | func isNNOutOfRange(ids IdsManager, vm *VirtualMachine) error { 25 | a, err := ids.GetFelt("a", vm) 26 | if err != nil { 27 | return err 28 | } 29 | op := FeltZero().Sub(a).Sub(FeltOne()) 30 | bound := FeltOne().Shl(16 * builtins.RANGE_CHECK_N_PARTS) 31 | if op.Cmp(bound) == -1 { 32 | return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) 33 | } 34 | return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltOne())) 35 | } 36 | 37 | // memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1 38 | func isLeFelt(ids IdsManager, vm *VirtualMachine) error { 39 | a, err := ids.GetFelt("a", vm) 40 | if err != nil { 41 | return err 42 | } 43 | b, err := ids.GetFelt("b", vm) 44 | if err != nil { 45 | return err 46 | } 47 | if a.Cmp(b) != 1 { 48 | return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) 49 | } 50 | return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltOne())) 51 | } 52 | -------------------------------------------------------------------------------- /pkg/hints/memcpy_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 9 | ) 10 | 11 | // Implements hint: memory[ap] = segments.add() 12 | func add_segment(vm *VirtualMachine) error { 13 | new_segment_base := vm.Segments.AddSegment() 14 | return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableRelocatable(new_segment_base)) 15 | } 16 | 17 | // Implements hint: 18 | // %{ vm_exit_scope() %} 19 | func vm_exit_scope(executionScopes *ExecutionScopes) error { 20 | return executionScopes.ExitScope() 21 | } 22 | 23 | // Implements hint: 24 | // %{ vm_enter_scope({'n': ids.len}) %} 25 | func memcpy_enter_scope(ids IdsManager, vm *VirtualMachine, execScopes *ExecutionScopes) error { 26 | len, err := ids.GetFelt("len", vm) 27 | if err != nil { 28 | return err 29 | } 30 | scope := map[string]interface{}{"n": len} 31 | execScopes.EnterScope(scope) 32 | return nil 33 | } 34 | 35 | /* 36 | Implements hint: 37 | 38 | %{ 39 | n -= 1 40 | ids.`i_name` = 1 if n > 0 else 0 41 | 42 | %} 43 | */ 44 | func memset_step_loop(ids IdsManager, vm *VirtualMachine, execScoes *ExecutionScopes, i_name string) error { 45 | // get `n` variable from vm scope 46 | n, err := execScoes.Get("n") 47 | if err != nil { 48 | return err 49 | } 50 | // this variable will hold the value of `n - 1` 51 | newN, ok := n.(Felt) 52 | if !ok { 53 | return ConversionError(n, "felt") 54 | } 55 | newN = newN.Sub(FeltOne()) 56 | execScoes.AssignOrUpdateVariable("n", newN) 57 | 58 | // if `newN` is positive, insert 1 in the address of `continue_loop` 59 | // else, insert 0 60 | var flag *MaybeRelocatable 61 | if newN.IsPositive() { 62 | flag = NewMaybeRelocatableFelt(FeltOne()) 63 | } else { 64 | flag = NewMaybeRelocatableFelt(FeltZero()) 65 | } 66 | return ids.Insert(i_name, flag, vm) 67 | } 68 | 69 | // Implements hint: vm_enter_scope() 70 | func vm_enter_scope(executionScopes *ExecutionScopes) error { 71 | executionScopes.EnterScope(make(map[string]interface{})) 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /pkg/hints/memset_hint_codes.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | const MEMSET_ENTER_SCOPE = "vm_enter_scope({'n': ids.n})" 4 | const MEMSET_CONTINUE_LOOP = "n -= 1\nids.continue_loop = 1 if n > 0 else 0" 5 | -------------------------------------------------------------------------------- /pkg/hints/memset_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 7 | ) 8 | 9 | // Implements hint: 10 | // %{ vm_enter_scope({'n': ids.n}) %} 11 | func memset_enter_scope(ids IdsManager, vm *VirtualMachine, execScopes *ExecutionScopes) error { 12 | n, err := ids.GetFelt("n", vm) 13 | if err != nil { 14 | return err 15 | } 16 | execScopes.EnterScope(map[string]interface{}{"n": n}) 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /pkg/hints/pow_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 8 | ) 9 | 10 | // Implements hint: 11 | // %{ ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1 %} 12 | func pow(ids IdsManager, vm *VirtualMachine) error { 13 | prev_locs_exp_addr, err := ids.GetRelocatable("prev_locs", vm) 14 | if err != nil { 15 | return err 16 | } 17 | 18 | prev_locs_exp, err := vm.Segments.Memory.GetFelt(prev_locs_exp_addr.AddUint(4)) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | return ids.Insert("locs", NewMaybeRelocatableFelt(prev_locs_exp.And(FeltOne())), vm) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/hints/pow_hints_test.go: -------------------------------------------------------------------------------- 1 | package hints_test 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 10 | "testing" 11 | ) 12 | 13 | func TestPowHintOddOk(t *testing.T) { 14 | vm := NewVirtualMachine() 15 | vm.Segments.AddSegment() 16 | vm.Segments.Memory.Insert(NewRelocatable(0, 4), NewMaybeRelocatableFelt(FeltFromUint64(3))) 17 | 18 | idsManager := SetupIdsForTest( 19 | map[string][]*MaybeRelocatable{ 20 | "prev_locs": {NewMaybeRelocatableRelocatable(NewRelocatable(0, 0))}, 21 | "locs": {nil}, 22 | }, 23 | vm, 24 | ) 25 | hintProcessor := CairoVmHintProcessor{} 26 | hintData := any(HintData{ 27 | Ids: idsManager, 28 | Code: POW, 29 | }) 30 | 31 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 32 | if err != nil { 33 | t.Errorf("POW hint test failed with error %s", err) 34 | } 35 | 36 | locs, err := idsManager.GetFelt("locs", vm) 37 | if err != nil { 38 | t.Errorf("Failed to get locs.bit with error: %s", err) 39 | } 40 | 41 | if locs != FeltOne() { 42 | t.Errorf("locs.bit: %d != 1", locs) 43 | } 44 | } 45 | 46 | func TestPowHintEvenOk(t *testing.T) { 47 | vm := NewVirtualMachine() 48 | vm.Segments.AddSegment() 49 | vm.Segments.Memory.Insert(NewRelocatable(0, 4), NewMaybeRelocatableFelt(FeltFromUint64(2))) 50 | 51 | idsManager := SetupIdsForTest( 52 | map[string][]*MaybeRelocatable{ 53 | "prev_locs": {NewMaybeRelocatableRelocatable(NewRelocatable(0, 0))}, 54 | "locs": {nil}, 55 | }, 56 | vm, 57 | ) 58 | hintProcessor := CairoVmHintProcessor{} 59 | hintData := any(HintData{ 60 | Ids: idsManager, 61 | Code: POW, 62 | }) 63 | 64 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 65 | if err != nil { 66 | t.Errorf("POW hint test failed with error %s", err) 67 | } 68 | 69 | locs, err := idsManager.GetFelt("locs", vm) 70 | if err != nil { 71 | t.Errorf("Failed to get locs.bit with error: %s", err) 72 | } 73 | 74 | if locs != FeltZero() { 75 | t.Errorf("locs.bit: %d != 0", locs) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /pkg/hints/secp_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | "math/big" 5 | 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 7 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 10 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 11 | "github.com/pkg/errors" 12 | ) 13 | 14 | func reduceV1(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { 15 | secpP := SECP_P() 16 | scopes.AssignOrUpdateVariable("SECP_P", secpP) 17 | value, err := Uint384FromVarName("x", ids, vm) 18 | if err != nil { 19 | return err 20 | } 21 | packedValue := value.Pack86() 22 | scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP)) 23 | return nil 24 | } 25 | 26 | func reduceV2(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { 27 | secpP, err := FetchScopeVar[big.Int]("SECP_P", scopes) 28 | if err != nil { 29 | return err 30 | } 31 | value, err := Uint384FromVarName("x", ids, vm) 32 | if err != nil { 33 | return err 34 | } 35 | packedValue := value.Pack86() 36 | scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP)) 37 | return nil 38 | } 39 | 40 | func reduceED25519(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { 41 | secpP := SECP_P_V2() 42 | scopes.AssignOrUpdateVariable("SECP_P", secpP) 43 | value, err := Uint384FromVarName("x", ids, vm) 44 | if err != nil { 45 | return err 46 | } 47 | packedValue := value.Pack86() 48 | scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP)) 49 | return nil 50 | } 51 | 52 | func verifyZero(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, secpP big.Int) error { 53 | scopes.AssignOrUpdateVariable("SECP_P", secpP) 54 | valUnpacked, err := Uint384FromVarName("val", ids, vm) 55 | if err != nil { 56 | return err 57 | } 58 | val := valUnpacked.Pack86() 59 | q, r := new(big.Int).DivMod(&val, &secpP, new(big.Int)) 60 | if r.Cmp(big.NewInt(0)) != 0 { 61 | return errors.Errorf("verify_zero: Invalid input %s", val.Text(10)) 62 | } 63 | return ids.Insert("q", memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(q)), vm) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/hints/set_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 8 | "github.com/pkg/errors" 9 | "reflect" 10 | ) 11 | 12 | /* 13 | Implements hint: 14 | 15 | assert ids.elm_size > 0 16 | assert ids.set_ptr <= ids.set_end_ptr 17 | elm_list = memory.get_range(ids.elm_ptr, ids.elm_size) 18 | for i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size): 19 | 20 | if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list: 21 | ids.index = i // ids.elm_size 22 | ids.is_elm_in_set = 1 23 | break 24 | 25 | else: 26 | 27 | ids.is_elm_in_set = 0 28 | */ 29 | func setAdd(ids IdsManager, vm *VirtualMachine) error { 30 | setPtr, err := ids.GetRelocatable("set_ptr", vm) 31 | if err != nil { 32 | return err 33 | } 34 | elmSizeFelt, err := ids.GetFelt("elm_size", vm) 35 | if err != nil { 36 | return err 37 | } 38 | elmPtr, err := ids.GetRelocatable("elm_ptr", vm) 39 | if err != nil { 40 | return err 41 | } 42 | setEndPtr, err := ids.GetRelocatable("set_end_ptr", vm) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | if elmSizeFelt.IsZero() { 48 | return errors.Errorf("assert ids.elm_size > 0") 49 | } 50 | 51 | elmSize, err := elmSizeFelt.ToUint() 52 | 53 | if err != nil { 54 | return err 55 | } 56 | 57 | if setPtr.Offset > setEndPtr.Offset { 58 | return errors.Errorf("expected set_ptr: %v <= set_end_ptr: %v", setPtr, setEndPtr) 59 | } 60 | 61 | elem, err := vm.Segments.Memory.GetRange(elmPtr, elmSize) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | for i := uint(0); i < setEndPtr.Offset-setPtr.Offset-elmSize; i++ { 67 | otherElm, err := vm.Segments.Memory.GetRange(setPtr.AddUint(i*elmSize), elmSize) 68 | if err != nil { 69 | return err 70 | } 71 | if reflect.DeepEqual(elem, otherElm) { 72 | err := ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) 73 | if err != nil { 74 | return err 75 | } 76 | return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltOne()), vm) 77 | } 78 | } 79 | 80 | return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltZero()), vm) 81 | } 82 | -------------------------------------------------------------------------------- /pkg/hints/set_hints_test.go: -------------------------------------------------------------------------------- 1 | package hints_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 10 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 11 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 12 | ) 13 | 14 | func TestSetAddElmInSet(t *testing.T) { 15 | vm := NewVirtualMachine() 16 | // Initialize segments 17 | vm.Segments.AddSegment() 18 | vm.Segments.AddSegment() 19 | // element to insert 20 | vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(2))) 21 | // set 22 | vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(1))) 23 | vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(2))) 24 | idsManager := SetupIdsForTest( 25 | map[string][]*MaybeRelocatable{ 26 | "elm_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, 27 | "set_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 1))}, 28 | "set_end_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 4))}, 29 | "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(1))}, 30 | "index": {nil}, 31 | "is_elm_in_set": {nil}, 32 | }, 33 | vm, 34 | ) 35 | 36 | hintProcessor := CairoVmHintProcessor{} 37 | hintData := any(HintData{ 38 | Ids: idsManager, 39 | Code: SET_ADD, 40 | }) 41 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 42 | if err != nil { 43 | t.Errorf("SET_ADD failed with error: %s", err) 44 | } 45 | 46 | isElmInSet, err := idsManager.GetFelt("is_elm_in_set", vm) 47 | if err != nil { 48 | t.Errorf("SET_ADD couldn't get is_elm_in_set: %s", err) 49 | } 50 | 51 | if !isElmInSet.IsOne() { 52 | t.Errorf("Expected is_elm_in_set to be 1, got: %s", isElmInSet.ToSignedFeltString()) 53 | } 54 | 55 | index, err := idsManager.GetFelt("index", vm) 56 | if err != nil { 57 | t.Errorf("SET_ADD couldn't get index: %s", err) 58 | } 59 | if !index.IsOne() { 60 | t.Errorf("Expected element to be found at 1, got index: %s", index.ToSignedFeltString()) 61 | } 62 | } 63 | 64 | func TestSetAddElmNotInSet(t *testing.T) { 65 | vm := NewVirtualMachine() 66 | // Initialize segments 67 | vm.Segments.AddSegment() 68 | vm.Segments.AddSegment() 69 | // element to insert 70 | vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(3))) 71 | // set 72 | vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(1))) 73 | vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(2))) 74 | idsManager := SetupIdsForTest( 75 | map[string][]*MaybeRelocatable{ 76 | "elm_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, 77 | "set_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 1))}, 78 | "set_end_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 3))}, 79 | "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(1))}, 80 | "index": {nil}, 81 | "is_elm_in_set": {nil}, 82 | }, 83 | vm, 84 | ) 85 | 86 | hintProcessor := CairoVmHintProcessor{} 87 | hintData := any(HintData{ 88 | Ids: idsManager, 89 | Code: SET_ADD, 90 | }) 91 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 92 | if err != nil { 93 | t.Errorf("SET_ADD failed with error: %s", err) 94 | } 95 | 96 | isElmInSet, err := idsManager.GetFelt("is_elm_in_set", vm) 97 | if err != nil { 98 | t.Errorf("SET_ADD couldn't get is_elm_in_set: %s", err) 99 | } 100 | 101 | if !isElmInSet.IsZero() { 102 | t.Errorf("Expected is_elm_in_set to be 1, got: %s", isElmInSet.ToSignedFeltString()) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /pkg/hints/sha256_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 8 | ) 9 | 10 | func sha256Input(ids IdsManager, vm *VirtualMachine) error { 11 | nBytes, err := ids.GetFelt("n_bytes", vm) 12 | if err != nil { 13 | return err 14 | } 15 | if nBytes.Cmp(FeltFromUint(4)) != -1 { 16 | return ids.Insert("full_word", NewMaybeRelocatableFelt(FeltOne()), vm) 17 | } 18 | return ids.Insert("full_word", NewMaybeRelocatableFelt(FeltZero()), vm) 19 | } 20 | -------------------------------------------------------------------------------- /pkg/hints/sha256_hints_test.go: -------------------------------------------------------------------------------- 1 | package hints_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 10 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 11 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 12 | ) 13 | 14 | func TestSha256InputFalse(t *testing.T) { 15 | vm := NewVirtualMachine() 16 | vm.Segments.AddSegment() 17 | idsManager := SetupIdsForTest( 18 | map[string][]*MaybeRelocatable{ 19 | "n_bytes": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, 20 | "full_word": {nil}, 21 | }, 22 | vm, 23 | ) 24 | hintProcessor := CairoVmHintProcessor{} 25 | hintData := any(HintData{ 26 | Ids: idsManager, 27 | Code: SHA256_INPUT, 28 | }) 29 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 30 | if err != nil { 31 | t.Errorf("SHA256_INPUT hint test failed with error %s", err) 32 | } 33 | // Check ids.full_word 34 | fullWord, err := idsManager.GetFelt("full_word", vm) 35 | if err != nil || fullWord.Cmp(FeltZero()) != 0 { 36 | t.Error("Wrong/No value inserted into ids.full_word") 37 | } 38 | } 39 | 40 | func TestSha256InputTrue(t *testing.T) { 41 | vm := NewVirtualMachine() 42 | vm.Segments.AddSegment() 43 | idsManager := SetupIdsForTest( 44 | map[string][]*MaybeRelocatable{ 45 | "n_bytes": {NewMaybeRelocatableFelt(FeltFromUint64(8))}, 46 | "full_word": {nil}, 47 | }, 48 | vm, 49 | ) 50 | hintProcessor := CairoVmHintProcessor{} 51 | hintData := any(HintData{ 52 | Ids: idsManager, 53 | Code: SHA256_INPUT, 54 | }) 55 | err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) 56 | if err != nil { 57 | t.Errorf("SHA256_INPUT hint test failed with error %s", err) 58 | } 59 | // Check ids.full_word 60 | fullWord, err := idsManager.GetFelt("full_word", vm) 61 | if err != nil || fullWord.Cmp(FeltOne()) != 0 { 62 | t.Error("Wrong/No value inserted into ids.full_word") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pkg/hints/signature_hints.go: -------------------------------------------------------------------------------- 1 | package hints 2 | 3 | import ( 4 | "math/big" 5 | 6 | . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/types" 9 | "github.com/lambdaclass/cairo-vm.go/pkg/utils" 10 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 11 | ) 12 | 13 | func divModNPacked(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, n *big.Int) error { 14 | a, err := Uint384FromVarName("a", ids, vm) 15 | if err != nil { 16 | return err 17 | } 18 | b, err := Uint384FromVarName("b", ids, vm) 19 | if err != nil { 20 | return err 21 | } 22 | packedA := a.Pack86() 23 | packedB := b.Pack86() 24 | 25 | val, err := utils.DivMod(&packedA, &packedB, n) 26 | if err != nil { 27 | return err 28 | } 29 | 30 | scopes.AssignOrUpdateVariable("a", packedA) 31 | scopes.AssignOrUpdateVariable("b", packedB) 32 | scopes.AssignOrUpdateVariable("value", *val) 33 | scopes.AssignOrUpdateVariable("res", *val) 34 | 35 | return nil 36 | } 37 | 38 | func divModNPackedDivMod(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { 39 | n, _ := new(big.Int).SetString("115792089237316195423570985008687907852837564279074904382605163141518161494337", 10) 40 | scopes.AssignOrUpdateVariable("N", *n) 41 | return divModNPacked(ids, vm, scopes, n) 42 | } 43 | 44 | func divModNPackedDivModExternalN(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { 45 | n, err := FetchScopeVar[big.Int]("N", scopes) 46 | if err != nil { 47 | return err 48 | } 49 | return divModNPacked(ids, vm, scopes, &n) 50 | } 51 | 52 | func divModNSafeDiv(ids IdsManager, scopes *ExecutionScopes, aAlias string, bAlias string, addOne bool) error { 53 | // Fetch scope variables 54 | a, err := FetchScopeVar[big.Int](aAlias, scopes) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | b, err := FetchScopeVar[big.Int](bAlias, scopes) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | res, err := FetchScopeVar[big.Int]("res", scopes) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | n, err := FetchScopeVar[big.Int]("N", scopes) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | // Hint logic 75 | value, err := utils.SafeDivBig(new(big.Int).Sub(new(big.Int).Mul(&res, &b), &a), &n) 76 | if err != nil { 77 | return err 78 | } 79 | if addOne { 80 | value = new(big.Int).Add(value, big.NewInt(1)) 81 | } 82 | // Update scope 83 | scopes.AssignOrUpdateVariable("value", *value) 84 | return nil 85 | } 86 | 87 | func getPointFromX(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, constants *map[string]Felt) error { 88 | // Handle scope & ids variables 89 | secpP := SECP_P() 90 | scopes.AssignOrUpdateVariable("SECP_P", secpP) 91 | betaFelt, err := ids.GetConst("BETA", constants) 92 | if err != nil { 93 | return err 94 | } 95 | beta := new(big.Int).Mod(betaFelt.ToBigInt(), &secpP) 96 | xCubeIntUnpacked, err := Uint384FromVarName("x_cube", ids, vm) 97 | if err != nil { 98 | return err 99 | } 100 | xCube := xCubeIntUnpacked.Pack86() 101 | vFelt, err := ids.GetFelt("v", vm) 102 | v := vFelt.ToBigInt() 103 | if err != nil { 104 | return err 105 | } 106 | // Hint logic 107 | yCube := new(big.Int).Mod(new(big.Int).Add(&xCube, beta), &secpP) 108 | // y = (yCube ** ((SECP_P + 1) << 2)) % SECP_P 109 | y := new(big.Int).Exp(yCube, new(big.Int).Rsh(new(big.Int).Add(&secpP, big.NewInt(1)), 2), &secpP) 110 | if utils.IsEven(v) != utils.IsEven(y) { 111 | y = new(big.Int).Sub(&secpP, y) 112 | } 113 | scopes.AssignOrUpdateVariable("value", *y) 114 | return nil 115 | } 116 | -------------------------------------------------------------------------------- /pkg/lambdaworks/lib/.gitignore: -------------------------------------------------------------------------------- 1 | liblambdaworks.a 2 | liblambdaworks.so 3 | -------------------------------------------------------------------------------- /pkg/lambdaworks/lib/lambdaworks.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef uint64_t limb_t; 6 | typedef unsigned int uint_t; 7 | 8 | /* A 256 bit prime field element (felt), represented as four limbs (integers). 9 | */ 10 | typedef limb_t felt_t[4]; 11 | 12 | /* Gets a felt_t representing the "value" number, in montgomery format. */ 13 | void from(felt_t result, uint64_t value); 14 | 15 | /* Gets a felt_t representing the "value" number, in montgomery format. */ 16 | void from_uint(felt_t result, uint_t value); 17 | 18 | /*Gets a felt_t representing the "value" hexadecimal string, in montgomery 19 | * format. */ 20 | void from_hex(felt_t result, char *value); 21 | 22 | /*Gets a felt_t representing the "value" decimal string, in montgomery format. 23 | */ 24 | void from_dec_str(felt_t result, char *value); 25 | 26 | /* Converts a felt_t to bytes in little-endian representation. */ 27 | void to_le_bytes(uint8_t result[32], felt_t value); 28 | 29 | /* Converts a felt_t to bytes in big-endian representation. */ 30 | void to_be_bytes(uint8_t result[32], felt_t value); 31 | 32 | /* Converts a felt_t to its digits in little_endian. */ 33 | void to_le_digits(uint8_t result[32], felt_t value); 34 | 35 | /* Converts a felt_t to a String representation. */ 36 | void to_hex_string(char *string, felt_t value); 37 | 38 | /* Converts an array of bytes in little-endian representation to a felt_t. */ 39 | void from_le_bytes(felt_t result, uint8_t bytes[32]); 40 | 41 | /* Converts an array of bytes in big-endian representation to a felt_t. */ 42 | void from_be_bytes(felt_t result, uint8_t bytes[32]); 43 | 44 | /* Gets a felt_t representing 0 */ 45 | void zero(felt_t result); 46 | 47 | /* Gets a felt_t representing 1 */ 48 | void one(felt_t result); 49 | 50 | void signed_felt_max_value(felt_t result); 51 | 52 | /* Writes the result variable with the sum of a and b felts. */ 53 | void add(felt_t a, felt_t b, felt_t result); 54 | 55 | /* Writes the result variable with a - b. */ 56 | void sub(felt_t a, felt_t b, felt_t result); 57 | 58 | /* Writes the result variable with a * b. */ 59 | void mul(felt_t a, felt_t b, felt_t result); 60 | 61 | /* Writes the result variable with a / b. */ 62 | void lw_div(felt_t a, felt_t b, felt_t result); 63 | 64 | /* Returns the minimum number of bits needed to represent the felt */ 65 | limb_t bits(felt_t a); 66 | 67 | /* writes the result variable with a & b */ 68 | void felt_and(felt_t a, felt_t b, felt_t result); 69 | 70 | /* writes the result variable with a | b */ 71 | void felt_or(felt_t a, felt_t b, felt_t result); 72 | 73 | /* writes the result variable with a ^ b */ 74 | void felt_xor(felt_t a, felt_t b, felt_t result); 75 | 76 | /* writes the result variable with a << num */ 77 | void felt_shl(felt_t a, uint64_t num, felt_t result); 78 | 79 | /* writes the result variable with a.pow(num) */ 80 | void felt_pow_uint(felt_t a, uint32_t num, felt_t result); 81 | 82 | /* writes the result variable with a.pow(exponent) */ 83 | void felt_pow(felt_t a, felt_t p, felt_t result); 84 | 85 | void felt_sqrt(felt_t a, felt_t result); 86 | 87 | /* returns the representation of a felt to string */ 88 | char *to_signed_felt(felt_t value); 89 | 90 | /* frees a pointer to a string */ 91 | void free_string(char *ptr); 92 | 93 | /* writes the result variable with a >> num */ 94 | void felt_shr(felt_t a, size_t b, felt_t result); 95 | 96 | /* Writes the div & rem variables with a.div_rem(b). */ 97 | void div_rem(felt_t a, felt_t b, felt_t div, felt_t rem); 98 | 99 | /* 100 | Compares x and y and returns: 101 | -1 if a < b 102 | 0 if a == b 103 | +1 if a > b 104 | */ 105 | int cmp(felt_t a, felt_t b); 106 | -------------------------------------------------------------------------------- /pkg/lambdaworks/lib/lambdaworks/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | 17 | # Added by cargo 18 | 19 | /target 20 | -------------------------------------------------------------------------------- /pkg/lambdaworks/lib/lambdaworks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | libc = "0.2" 10 | lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git" } 11 | lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git" } 12 | num-bigint = { version = "0.4", default-features = false } 13 | lazy_static = "1.4.0" 14 | 15 | [lib] 16 | crate-type = ["cdylib", "staticlib", "lib"] 17 | -------------------------------------------------------------------------------- /pkg/layouts/diluted_pool_instance_def.go: -------------------------------------------------------------------------------- 1 | package layouts 2 | 3 | type DilutedPoolInstanceDef struct { 4 | UnitsPerStep uint 5 | Spacing uint 6 | NBits uint 7 | } 8 | 9 | func DefaultDilutedPoolInstance() *DilutedPoolInstanceDef { 10 | return &DilutedPoolInstanceDef{UnitsPerStep: 16, Spacing: 4, NBits: 16} 11 | } 12 | -------------------------------------------------------------------------------- /pkg/layouts/layout.go: -------------------------------------------------------------------------------- 1 | package layouts 2 | 3 | import ( 4 | "github.com/lambdaclass/cairo-vm.go/pkg/builtins" 5 | ) 6 | 7 | // Representation of a cairo layout. 8 | // Stores the layout name and the particular builtin instances and 9 | // their configuration for it. 10 | type CairoLayout struct { 11 | Name string 12 | Builtins []builtins.BuiltinRunner 13 | // TODO - Add when necessary: 14 | // cpuComponentStep uint, 15 | RcUnits uint 16 | PublicMemoryFraction uint 17 | MemoryUnitsPerStep uint 18 | DilutedPoolInstance *DilutedPoolInstanceDef 19 | // nTraceColums uint 20 | // cpuInstanceDef CpuInstanceDef 21 | } 22 | 23 | func NewPlainLayout() CairoLayout { 24 | return CairoLayout{ 25 | Name: "plain", 26 | Builtins: []builtins.BuiltinRunner{builtins.NewOutputBuiltinRunner()}, 27 | RcUnits: 16, 28 | PublicMemoryFraction: 4, 29 | MemoryUnitsPerStep: 8, 30 | DilutedPoolInstance: nil, 31 | } 32 | } 33 | 34 | func NewSmallLayout() CairoLayout { 35 | return CairoLayout{ 36 | Name: "small", 37 | Builtins: []builtins.BuiltinRunner{ 38 | builtins.NewOutputBuiltinRunner(), 39 | builtins.NewPedersenBuiltinRunner(256), 40 | builtins.DefaultRangeCheckBuiltinRunner(), 41 | builtins.NewSignatureBuiltinRunner(2048), 42 | }, 43 | RcUnits: 16, 44 | PublicMemoryFraction: 4, 45 | MemoryUnitsPerStep: 8, 46 | DilutedPoolInstance: nil, 47 | } 48 | } 49 | 50 | func NewAllCairoLayout() CairoLayout { 51 | return CairoLayout{ 52 | Name: "all_cairo", 53 | Builtins: []builtins.BuiltinRunner{ 54 | builtins.NewOutputBuiltinRunner(), 55 | builtins.NewPedersenBuiltinRunner(256), 56 | builtins.DefaultRangeCheckBuiltinRunner(), 57 | builtins.NewSignatureBuiltinRunner(2048), 58 | builtins.NewBitwiseBuiltinRunner(16), 59 | builtins.NewEcOpBuiltinRunner(1024), 60 | builtins.NewKeccakBuiltinRunner(2048), 61 | builtins.NewPoseidonBuiltinRunner(256)}, 62 | RcUnits: 4, 63 | PublicMemoryFraction: 8, 64 | MemoryUnitsPerStep: 8, 65 | DilutedPoolInstance: DefaultDilutedPoolInstance(), 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pkg/parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "math/big" 7 | "os" 8 | 9 | "github.com/pkg/errors" 10 | ) 11 | 12 | type FlowTrackingData struct { 13 | APTracking ApTrackingData `json:"ap_tracking"` 14 | ReferenceIds map[string]uint `json:"reference_ids"` 15 | } 16 | 17 | type Location struct { 18 | EndCol int `json:"end_col"` 19 | EndLine int `json:"end_line"` 20 | InputFile map[string]string `json:"input_file"` 21 | StartCol int `json:"start_col"` 22 | StartLine int `json:"start_line"` 23 | } 24 | 25 | type InstructionLocation struct { 26 | AccessibleScopes []string `json:"accessible_scopes"` 27 | FlowTrackingData FlowTrackingData `json:"flow_tracking_data"` 28 | Hints []HintLocation `json:"hints"` 29 | Inst Location `json:"inst"` 30 | } 31 | 32 | type HintLocation struct { 33 | Location Location `json:"location"` 34 | NPrefixNewLines uint32 `json:"n_prefix_newlines"` 35 | } 36 | 37 | type DebugInfo struct { 38 | FileContents map[string]string `json:"file_contents"` 39 | InstructionLocation map[string]InstructionLocation `json:"instruction_locations"` 40 | } 41 | 42 | type Identifier struct { 43 | FullName string `json:"full_name"` 44 | Members map[string]any `json:"members"` 45 | Size int `json:"size"` 46 | Decorators []string `json:"decorators"` 47 | PC int `json:"pc"` 48 | Type string `json:"type"` 49 | CairoType string `json:"cairo_type"` 50 | Value big.Int `json:"value"` 51 | Destination string `json:"destination"` 52 | } 53 | 54 | type ApTrackingData struct { 55 | Group int `json:"group"` 56 | Offset int `json:"offset"` 57 | } 58 | 59 | type Reference struct { 60 | ApTrackingData ApTrackingData `json:"ap_tracking_data"` 61 | Pc int `json:"pc"` 62 | Value string `json:"value"` 63 | } 64 | 65 | type ReferenceManager struct { 66 | References []Reference `json:"references"` 67 | } 68 | 69 | type HintParams struct { 70 | Code string `json:"code"` 71 | AccessibleScopes []string `json:"accessible_scopes"` 72 | FlowTrackingData FlowTrackingData `json:"flow_tracking_data"` 73 | } 74 | 75 | type CompiledJson struct { 76 | Attributes interface{} `json:"attributes"` 77 | Builtins []string `json:"builtins"` 78 | CompilerVersion string `json:"compiler_version"` 79 | Data []string `json:"data"` 80 | DebugInfo DebugInfo `json:"debug_info"` 81 | Hints map[uint][]HintParams `json:"hints"` 82 | Identifiers map[string]Identifier `json:"identifiers"` 83 | MainScope string `json:"main_scope"` 84 | Prime string `json:"prime"` 85 | ReferenceManager ReferenceManager `json:"reference_manager"` 86 | } 87 | 88 | func ParserError(err error) error { 89 | return errors.Wrapf(err, "Parser error\n") 90 | } 91 | 92 | func Parse(jsonPath string) (CompiledJson, error) { 93 | jsonFile, err := os.Open(jsonPath) 94 | 95 | if err != nil { 96 | return CompiledJson{}, nil 97 | } 98 | defer jsonFile.Close() 99 | 100 | var cJson CompiledJson 101 | 102 | byteValue, _ := ioutil.ReadAll(jsonFile) 103 | err = json.Unmarshal(byteValue, &cJson) 104 | 105 | if err != nil { 106 | return CompiledJson{}, ParserError(err) 107 | } 108 | 109 | return cJson, nil 110 | 111 | } 112 | -------------------------------------------------------------------------------- /pkg/parser/parser_test.go: -------------------------------------------------------------------------------- 1 | package parser_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/lambdaclass/cairo-vm.go/pkg/parser" 8 | ) 9 | 10 | func TestData(t *testing.T) { 11 | got, err := parser.Parse("../../cairo_programs/fibonacci.json") 12 | if err != nil { 13 | t.Errorf("Test failed with error: %v", err) 14 | } 15 | expected := []string{"0x480680017fff8000", 16 | "0x1", 17 | "0x480680017fff8000", 18 | "0x1", 19 | "0x480680017fff8000", 20 | "0xa", 21 | "0x1104800180018000", 22 | "0x5", 23 | "0x400680017fff7fff", 24 | "0x90", 25 | "0x208b7fff7fff7ffe", 26 | "0x20780017fff7ffd", 27 | "0x5", 28 | "0x480a7ffc7fff8000", 29 | "0x480a7ffc7fff8000", 30 | "0x208b7fff7fff7ffe", 31 | "0x482a7ffc7ffb8000", 32 | "0x480a7ffc7fff8000", 33 | "0x48127ffe7fff8000", 34 | "0x482680017ffd8000", 35 | "0x800000000000011000000000000000000000000000000000000000000000000", 36 | "0x1104800180018000", 37 | "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff7", 38 | "0x208b7fff7fff7ffe"} 39 | if !reflect.DeepEqual(got.Data, expected) { 40 | t.Errorf("We should have this data %s, got %s", expected, got.Data) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/runners/execution_resources.go: -------------------------------------------------------------------------------- 1 | package runners 2 | 3 | type ExecutionResources struct { 4 | NSteps uint 5 | NMemoryHoles uint 6 | BuiltinsInstanceCounter map[string]uint 7 | } 8 | -------------------------------------------------------------------------------- /pkg/runners/security.go: -------------------------------------------------------------------------------- 1 | package runners 2 | 3 | import ( 4 | "github.com/lambdaclass/cairo-vm.go/pkg/builtins" 5 | "github.com/pkg/errors" 6 | ) 7 | 8 | /* 9 | Verify that the completed run in a runner is safe to be relocated and be 10 | used by other Cairo programs. 11 | 12 | Checks include: 13 | - (Only if `verifyBuiltins` is set to true) All accesses to the builtin segments must be within the range defined by 14 | the builtins themselves. 15 | - There must not be accesses to the program segment outside the program 16 | data range. This check will use the `programSegmentSize` instead of the program data length if available. 17 | - All addresses in memory must be real (not temporary) 18 | 19 | Note: Each builtin is responsible for checking its own segments' data. 20 | */ 21 | func VerifySecureRunner(runner *CairoRunner, verifyBuiltins bool, programSegmentSize *uint) error { 22 | programSize := uint(len(runner.Program.Data)) 23 | if programSegmentSize != nil { 24 | programSize = *programSegmentSize 25 | } 26 | // Get builtin segment info 27 | builtinNames := make(map[int]string) 28 | builtinSizes := make(map[int]uint) 29 | if verifyBuiltins { 30 | for i := 0; i < len(runner.Vm.BuiltinRunners); i++ { 31 | base, stopPtr, err := runner.Vm.BuiltinRunners[i].GetMemorySegmentAddresses() 32 | if err != nil { 33 | return err 34 | } 35 | builtinNames[base.SegmentIndex] = runner.Vm.BuiltinRunners[i].Name() 36 | builtinSizes[base.SegmentIndex] = stopPtr.Offset 37 | } 38 | } 39 | // Run memory checks 40 | for addr, val := range runner.Vm.Segments.Memory.Data { 41 | // Check out of bound accesses to builtin segment 42 | size, ok := builtinSizes[addr.SegmentIndex] 43 | if ok && addr.Offset >= size { 44 | return errors.Errorf("Out of bounds access to builtin segment %s at %s", builtinNames[addr.SegmentIndex], addr.ToString()) 45 | } 46 | // Check out of bound accesses to program segment 47 | if addr.SegmentIndex == runner.ProgramBase.SegmentIndex && addr.SegmentIndex >= int(programSize) { 48 | return errors.Errorf("Out of bounds access to program segment at %s", addr.ToString()) 49 | } 50 | // Check non-relocated temporary addresses 51 | if addr.SegmentIndex < 0 { 52 | return errors.Errorf("Security Error: Invalid Memory Value: temporary address not relocated: %s", addr.ToString()) 53 | } 54 | relVal, isRel := val.GetRelocatable() 55 | if isRel && relVal.SegmentIndex < 0 { 56 | return errors.Errorf("Security Error: Invalid Memory Value: temporary address not relocated: %s", relVal.ToString()) 57 | } 58 | } 59 | // Run builtin-specific checks 60 | for i := 0; i < len(runner.Vm.BuiltinRunners); i++ { 61 | err := builtins.RunSecurityChecksForBuiltin(runner.Vm.BuiltinRunners[i], &runner.Vm.Segments) 62 | if err != nil { 63 | return err 64 | } 65 | } 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /pkg/runners/security_test.go: -------------------------------------------------------------------------------- 1 | package runners_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/lambdaclass/cairo-vm.go/pkg/builtins" 7 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 8 | . "github.com/lambdaclass/cairo-vm.go/pkg/runners" 9 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm" 10 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 11 | ) 12 | 13 | func TestVerifySecureRunnerEmptyMemory(t *testing.T) { 14 | runner, _ := NewCairoRunner(Program{}, "all_cairo", false) 15 | runner.Initialize() 16 | err := VerifySecureRunner(runner, true, nil) 17 | if err != nil { 18 | t.Errorf("VerifySecureRunner failed with error: %s", err.Error()) 19 | } 20 | } 21 | 22 | func TestVerifySecureRunnerOutOfBoundsAccessProgram(t *testing.T) { 23 | runner, _ := NewCairoRunner(Program{}, "all_cairo", false) 24 | runner.Initialize() 25 | // Insert an element into the program segment to trigger out of bounds access to program segment error 26 | runner.Vm.Segments.Memory.Insert(runner.ProgramBase, NewMaybeRelocatableFelt(FeltOne())) 27 | err := VerifySecureRunner(runner, true, nil) 28 | if err == nil { 29 | t.Errorf("VerifySecureRunner should have failed") 30 | } 31 | } 32 | 33 | func TestVerifySecureRunnerOutOfBoundsAccessBuiltin(t *testing.T) { 34 | runner, _ := NewCairoRunner(Program{Builtins: []string{builtins.OUTPUT_BUILTIN_NAME}}, "all_cairo", false) 35 | runner.Initialize() 36 | stopPtr := uint(0) 37 | runner.Vm.BuiltinRunners[0].(*builtins.OutputBuiltinRunner).StopPtr = &stopPtr 38 | // Insert an element into the output segment to trigger out of bounds access to builtin segment error 39 | runner.Vm.Segments.Memory.Insert(runner.Vm.BuiltinRunners[0].Base(), NewMaybeRelocatableFelt(FeltOne())) 40 | err := VerifySecureRunner(runner, true, nil) 41 | if err == nil { 42 | t.Errorf("VerifySecureRunner should have failed") 43 | } 44 | } 45 | 46 | func TestVerifySecureRunnerTemporaryVal(t *testing.T) { 47 | runner, _ := NewCairoRunner(Program{}, "all_cairo", false) 48 | runner.Initialize() 49 | // Insert a temporary address into memory 50 | runner.Vm.Segments.Memory.Insert(NewRelocatable(1, 7), NewMaybeRelocatableRelocatable(NewRelocatable(-1, 0))) 51 | err := VerifySecureRunner(runner, true, nil) 52 | if err == nil { 53 | t.Errorf("VerifySecureRunner should have failed") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/starknet_crypto/lib/.gitignore: -------------------------------------------------------------------------------- 1 | libstarknet_crypto.a 2 | libstarknet_crypto.so 3 | -------------------------------------------------------------------------------- /pkg/starknet_crypto/lib/starknet_crypto.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef uint8_t byte_t; 5 | 6 | // A 252 bit prime field element (felt), represented as an array of 32 bytes. 7 | typedef byte_t felt_t[32]; 8 | 9 | // Computes the poseidon hash permutation over a state of three felts 10 | void poseidon_permute(felt_t, felt_t, felt_t); 11 | 12 | void pedersen_hash(felt_t, felt_t, felt_t); 13 | 14 | bool verify_signature(felt_t, felt_t, felt_t, felt_t); 15 | -------------------------------------------------------------------------------- /pkg/starknet_crypto/lib/starknet_crypto/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | 17 | # Added by cargo 18 | 19 | /target 20 | 21 | -------------------------------------------------------------------------------- /pkg/starknet_crypto/lib/starknet_crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "starknet-crypto" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | libc = "0.2" 10 | starknet-crypto = { version = "0.5.0"} 11 | 12 | [lib] 13 | crate-type = ["cdylib", "staticlib", "lib"] 14 | -------------------------------------------------------------------------------- /pkg/starknet_crypto/lib/starknet_crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | use starknet_crypto::{poseidon_permute_comp, FieldElement, pedersen_hash as starknet_crypto_pedersen_hash, verify}; 2 | extern crate libc; 3 | 4 | // C representation of a bit array: a raw pointer to a mutable unsigned 8 bits integer. 5 | type Bytes = *mut u8; 6 | 7 | fn field_element_from_bytes(bytes: Bytes) -> FieldElement { 8 | let array = unsafe { 9 | let slice: &mut [u8] = std::slice::from_raw_parts_mut(bytes, 32); 10 | let array: [u8; 32] = slice.try_into().unwrap(); 11 | array 12 | }; 13 | FieldElement::from_bytes_be(&array).unwrap() 14 | } 15 | 16 | fn bytes_from_field_element(felt: FieldElement, bytes: Bytes) { 17 | let byte_array = felt.to_bytes_be(); 18 | for i in 0..32 { 19 | unsafe { 20 | *bytes.offset(i) = byte_array[i as usize]; 21 | } 22 | } 23 | } 24 | 25 | #[no_mangle] 26 | extern "C" fn poseidon_permute( 27 | first_state_felt: Bytes, 28 | second_state_felt: Bytes, 29 | third_state_felt: Bytes, 30 | ) { 31 | // Convert state from C representation to FieldElement 32 | let mut state_array: [FieldElement; 3] = [ 33 | field_element_from_bytes(first_state_felt), 34 | field_element_from_bytes(second_state_felt), 35 | field_element_from_bytes(third_state_felt), 36 | ]; 37 | // Call poseidon permute comp 38 | poseidon_permute_comp(&mut state_array); 39 | // Convert state from FieldElement back to C representation 40 | bytes_from_field_element(state_array[0], first_state_felt); 41 | bytes_from_field_element(state_array[1], second_state_felt); 42 | bytes_from_field_element(state_array[2], third_state_felt); 43 | } 44 | 45 | #[no_mangle] 46 | extern "C" fn pedersen_hash( 47 | felt_1: Bytes, 48 | felt_2: Bytes, 49 | result: Bytes, 50 | ){ 51 | // Convert Felts from C representation to FieldElement 52 | let f1 = field_element_from_bytes(felt_1); 53 | let f2 = field_element_from_bytes(felt_2); 54 | 55 | // Call starknet_crypto::pedersen_hash 56 | let hash_in_felt = starknet_crypto_pedersen_hash(&f1, &f2); 57 | bytes_from_field_element(hash_in_felt, result); 58 | } 59 | 60 | #[no_mangle] 61 | extern "C" fn verify_signature( 62 | public_key_bytes: Bytes, 63 | message_bytes: Bytes, 64 | r_bytes: Bytes, 65 | s_bytes: Bytes 66 | ) -> bool { 67 | let public_key = field_element_from_bytes(public_key_bytes); 68 | let message = field_element_from_bytes(message_bytes); 69 | let r = field_element_from_bytes(r_bytes); 70 | let s = field_element_from_bytes(s_bytes); 71 | let verification_result = verify(&public_key, &message, &r, &s); 72 | 73 | // An error on the verification is an invalid signature 74 | // That shouldn't verify 75 | match verification_result { 76 | Ok(verifies) => verifies, 77 | Err(_) => false 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /pkg/starknet_crypto/starknet_crypto.go: -------------------------------------------------------------------------------- 1 | package starknet_crypto 2 | 3 | /* 4 | #cgo LDFLAGS: pkg/starknet_crypto/lib/libstarknet_crypto.a -ldl 5 | #include "lib/starknet_crypto.h" 6 | #include 7 | */ 8 | import "C" 9 | import ( 10 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 11 | ) 12 | 13 | // Converts a Go Felt to a C felt_t. 14 | func toC(f lambdaworks.Felt) C.felt_t { 15 | var result C.felt_t 16 | for i, byte := range f.ToBeBytes() { 17 | result[i] = C.byte_t(byte) 18 | } 19 | return result 20 | } 21 | 22 | // Converts a C felt_t to a Go Felt. 23 | func fromC(result C.felt_t) lambdaworks.Felt { 24 | var bytes [32]uint8 25 | for i, byte := range result { 26 | bytes[i] = uint8(byte) 27 | } 28 | return lambdaworks.FeltFromBeBytes(&bytes) 29 | } 30 | 31 | func PoseidonPermuteComp(poseidon_state *[3]lambdaworks.Felt) { 32 | state := *poseidon_state 33 | // Convert args to c representation 34 | first_state_felt := toC(state[0]) 35 | second_state_felt := toC(state[1]) 36 | third_state_felt := toC(state[2]) 37 | 38 | // Compute hash using starknet_crypto C wrapper 39 | C.poseidon_permute(&first_state_felt[0], &second_state_felt[0], &third_state_felt[0]) 40 | // Convert result to Go representation 41 | var new_poseidon_state = [3]lambdaworks.Felt{ 42 | fromC(first_state_felt), 43 | fromC(second_state_felt), 44 | fromC(third_state_felt), 45 | } 46 | // Update poseidon state 47 | *poseidon_state = new_poseidon_state 48 | } 49 | 50 | func PedersenHash(f1 lambdaworks.Felt, f2 lambdaworks.Felt) lambdaworks.Felt { 51 | felt_1 := toC(f1) 52 | felt_2 := toC(f2) 53 | var result C.felt_t 54 | 55 | C.pedersen_hash(&felt_1[0], &felt_2[0], &result[0]) 56 | 57 | hash := fromC(result) 58 | 59 | return hash 60 | } 61 | 62 | func VerifySignature(public_key lambdaworks.Felt, message lambdaworks.Felt, r lambdaworks.Felt, s lambdaworks.Felt) bool { 63 | public_key_for_c := toC(public_key) 64 | message_for_c := toC(message) 65 | r_for_c := toC(r) 66 | s_for_c := toC(s) 67 | 68 | c_verify_status := C.verify_signature(&public_key_for_c[0], &message_for_c[0], &r_for_c[0], &s_for_c[0]) 69 | 70 | return bool(c_verify_status) 71 | } 72 | -------------------------------------------------------------------------------- /pkg/starknet_crypto/starknet_crypto_test.go: -------------------------------------------------------------------------------- 1 | package starknet_crypto_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 8 | starknet_crypto "github.com/lambdaclass/cairo-vm.go/pkg/starknet_crypto" 9 | ) 10 | 11 | func TestPoseidonPermuteCompA(t *testing.T) { 12 | // Set initial state values 13 | poseidon_state := [3]lambdaworks.Felt{ 14 | lambdaworks.FeltFromUint64(3), 15 | lambdaworks.FeltZero(), 16 | lambdaworks.FeltFromUint64(2), 17 | } 18 | // Run the poseidon permutation 19 | starknet_crypto.PoseidonPermuteComp(&poseidon_state) 20 | // Check final state values 21 | expected_poseidon_state := [3]lambdaworks.Felt{ 22 | lambdaworks.FeltFromHex("0x268c44203f1c763bca21beb5aec78b9063cdcdd0fdf6b598bb8e1e8f2b6253f"), 23 | lambdaworks.FeltFromHex("0x2b85c9f686f5d3036db55b2ca58a763a3065bc1bc8efbe0e70f3a7171f6cad3"), 24 | lambdaworks.FeltFromHex("0x61df3789eef0e1ee0dbe010582a00dd099191e6395dfb976e7be3be2fa9d54b"), 25 | } 26 | if !reflect.DeepEqual(poseidon_state, expected_poseidon_state) { 27 | t.Errorf("Wrong state after poseidon permutation.\n Expected %+v.\n Got: %+v", expected_poseidon_state, poseidon_state) 28 | } 29 | } 30 | 31 | func TestPoseidonPermuteCompB(t *testing.T) { 32 | // Set initial state values 33 | poseidon_state := [3]lambdaworks.Felt{ 34 | lambdaworks.FeltFromHex("0x268c44203f1c763bca21beb5aec78b9063cdcdd0fdf6b598bb8e1e8f2b6253f"), 35 | lambdaworks.FeltFromHex("0x2b85c9f686f5d3036db55b2ca58a763a3065bc1bc8efbe0e70f3a7171f6cad3"), 36 | lambdaworks.FeltFromHex("0x61df3789eef0e1ee0dbe010582a00dd099191e6395dfb976e7be3be2fa9d54b"), 37 | } 38 | // Run the poseidon permutation 39 | starknet_crypto.PoseidonPermuteComp(&poseidon_state) 40 | // Check final state values 41 | expected_poseidon_state := [3]lambdaworks.Felt{ 42 | lambdaworks.FeltFromHex("0x4ec565b1b01606b5222602b20f8ddc4a8a7c75b559b852ab183a0daf5930b5c"), 43 | lambdaworks.FeltFromHex("0x4d3c32c3c7cd39b6444db42e2437eeda12e459d28ce49a0f761a23d64c29e4c"), 44 | lambdaworks.FeltFromHex("0x749d4d0ddf41548e039f183b745a08b80fad54e9ac389021148350bdda70a92"), 45 | } 46 | if !reflect.DeepEqual(poseidon_state, expected_poseidon_state) { 47 | t.Errorf("Wrong state after poseidon permutation.\n Expected %+v.\n Got: %+v", expected_poseidon_state, poseidon_state) 48 | } 49 | } 50 | 51 | func TestPersenHash(t *testing.T) { 52 | // Set initial state values 53 | f1 := lambdaworks.FeltFromHex("0x20") 54 | f2 := lambdaworks.FeltFromHex("0x48") 55 | 56 | // Run the poseidon permutation 57 | hash := starknet_crypto.PedersenHash(f1, f2) 58 | 59 | if hash != lambdaworks.FeltFromHex("0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f") { 60 | t.Errorf("Error") 61 | } 62 | } 63 | 64 | func TestVerifySignatureShouldFail(t *testing.T) { 65 | signature := lambdaworks.FeltFromHex("0x1") 66 | msg_hash := lambdaworks.FeltFromHex("0x1") 67 | r := lambdaworks.FeltFromHex("0x1") 68 | s := lambdaworks.FeltFromHex("0x1") 69 | 70 | verified_signature := starknet_crypto.VerifySignature(signature, msg_hash, r, s) 71 | 72 | if verified_signature { 73 | t.Errorf("Verified a bad signature") 74 | } 75 | } 76 | 77 | func TestVerifyGoodSignature(t *testing.T) { 78 | 79 | stark_key := lambdaworks.FeltFromHex( 80 | "01ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca", 81 | ) 82 | msg_hash := lambdaworks.FeltFromHex( 83 | "0000000000000000000000000000000000000000000000000000000000000002", 84 | ) 85 | r_felt := lambdaworks.FeltFromHex( 86 | "0411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20", 87 | ) 88 | s_felt := lambdaworks.FeltFromHex( 89 | "0405c3191ab3883ef2b763af35bc5f5d15b3b4e99461d70e84c654a351a7c81b", 90 | ) 91 | 92 | verified_signature := starknet_crypto.VerifySignature(stark_key, msg_hash, r_felt, s_felt) 93 | 94 | if !verified_signature { 95 | t.Errorf("Didn't verify a good signature") 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /pkg/types/exec_scope_utils.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | func NewExecutionScopesWithInitValue(key string, val interface{}) *ExecutionScopes { 4 | scopes := NewExecutionScopes() 5 | scopes.EnterScope(map[string]interface{}{key: val}) 6 | return scopes 7 | } 8 | -------------------------------------------------------------------------------- /pkg/types/exec_scopes.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | ) 6 | 7 | type ExecutionScopes struct { 8 | data []map[string]interface{} 9 | } 10 | 11 | var ErrCannotExitMainScop error = ExecutionScopesError(errors.Errorf("Cannot exit main scope.")) 12 | 13 | func ExecutionScopesError(err error) error { 14 | return errors.Wrapf(err, "Execution scopes error") 15 | } 16 | 17 | func ErrVariableNotInScope(varName string) error { 18 | return ExecutionScopesError(errors.Errorf("Variable %s not in scope", varName)) 19 | } 20 | 21 | func ErrVariableHasWrongType(varName string) error { 22 | return ExecutionScopesError(errors.Errorf("Scope variable %s has wrong type", varName)) 23 | } 24 | 25 | func NewExecutionScopes() *ExecutionScopes { 26 | data := make([]map[string]interface{}, 1) 27 | data[0] = make(map[string]interface{}) 28 | return &ExecutionScopes{data} 29 | } 30 | 31 | func (es *ExecutionScopes) EnterScope(newScopeLocals map[string]interface{}) { 32 | es.data = append(es.data, newScopeLocals) 33 | 34 | } 35 | 36 | func (es *ExecutionScopes) ExitScope() error { 37 | if len(es.data) < 2 { 38 | return ErrCannotExitMainScop 39 | } 40 | i := len(es.data) - 1 41 | es.data = es.data[:i] 42 | 43 | return nil 44 | } 45 | 46 | func (es *ExecutionScopes) getLocalVariablesMut() (*map[string]interface{}, error) { 47 | locals, err := es.GetLocalVariables() 48 | if err != nil { 49 | return nil, err 50 | } 51 | return &locals, nil 52 | } 53 | 54 | func (es *ExecutionScopes) GetLocalVariables() (map[string]interface{}, error) { 55 | if len(es.data) > 0 { 56 | return es.data[len(es.data)-1], nil 57 | } 58 | return nil, ExecutionScopesError(errors.Errorf("Every enter_scope() requires a corresponding exit_scope().")) 59 | } 60 | 61 | func (es *ExecutionScopes) DeleteVariable(varName string) { 62 | locals, err := es.getLocalVariablesMut() 63 | if err != nil { 64 | return 65 | } 66 | delete(*locals, varName) 67 | 68 | } 69 | 70 | func (es *ExecutionScopes) AssignOrUpdateVariable(varName string, varValue interface{}) { 71 | locals, err := es.getLocalVariablesMut() 72 | if err != nil { 73 | return 74 | } 75 | (*locals)[varName] = varValue 76 | } 77 | 78 | func (es *ExecutionScopes) Get(varName string) (interface{}, error) { 79 | locals, err := es.GetLocalVariables() 80 | if err != nil { 81 | return nil, err 82 | } 83 | val, prs := locals[varName] 84 | if !prs { 85 | return nil, ErrVariableNotInScope(varName) 86 | } 87 | return val, nil 88 | } 89 | 90 | // Generic version of ExecutionScopes.Get which also handles casting 91 | func FetchScopeVar[T interface{}](varName string, scopes *ExecutionScopes) (T, error) { 92 | locals, err := scopes.GetLocalVariables() 93 | if err != nil { 94 | return *new(T), err 95 | } 96 | valAny, prs := locals[varName] 97 | if !prs { 98 | return *new(T), ErrVariableNotInScope(varName) 99 | } 100 | val, ok := valAny.(T) 101 | if !ok { 102 | return *new(T), ErrVariableHasWrongType(varName) 103 | } 104 | return val, nil 105 | } 106 | -------------------------------------------------------------------------------- /pkg/utils/math_utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "math" 5 | "math/big" 6 | 7 | "github.com/pkg/errors" 8 | ) 9 | 10 | func NextPowOf2(n uint) uint { 11 | var k uint = 1 12 | for k < n { 13 | k = k << 1 14 | } 15 | return k 16 | } 17 | 18 | // Performs integer division between x and y; fails if x is not divisible by y. 19 | func SafeDiv(x uint, y uint) (uint, error) { 20 | if y == 0 { 21 | return 0, errors.New("Attempted to divide by zero") 22 | } 23 | rem := math.Remainder(float64(x), float64(y)) 24 | if rem != 0 { 25 | return 0, errors.Errorf("%d is not divisible by %d", x, y) 26 | } 27 | 28 | return x / y, nil 29 | } 30 | 31 | func MinInt(x int, y int) int { 32 | if x < y { 33 | return x 34 | } else { 35 | return y 36 | } 37 | } 38 | 39 | func MaxInt(x int, y int) int { 40 | if x > y { 41 | return x 42 | } else { 43 | return y 44 | } 45 | } 46 | 47 | func DivCeil(x uint, y uint) uint { 48 | q := x / y 49 | if x%y != 0 { 50 | q++ 51 | } 52 | return q 53 | } 54 | 55 | // Performs integer division between x and y; fails if x is not divisible by y. 56 | func SafeDivBig(x *big.Int, y *big.Int) (*big.Int, error) { 57 | if y.Cmp(big.NewInt(0)) == 0 { 58 | return &big.Int{}, errors.New("SafeDiv: Attempted to divide by zero") 59 | } 60 | q, r := x.DivMod(x, y, new(big.Int)) 61 | if r.Cmp(big.NewInt(0)) != 0 { 62 | return &big.Int{}, errors.Errorf("SafeDiv: %s is not divisible by %s", x.Text(10), y.Text(10)) 63 | } 64 | return q, nil 65 | } 66 | 67 | // Finds a nonnegative integer x < p such that (m * x) % p == n. 68 | func DivMod(n *big.Int, m *big.Int, p *big.Int) (*big.Int, error) { 69 | a, _, c := Igcdex(m, p) 70 | if c.Cmp(big.NewInt(1)) != 0 { 71 | return nil, errors.Errorf("Operation failed: divmod(%s, %s, %s), igcdex(%s, %s) != 1 ", n.Text(10), m.Text(10), p.Text(10), m.Text(10), p.Text(10)) 72 | } 73 | return new(big.Int).Mod(new(big.Int).Mul(n, a), p), nil 74 | } 75 | 76 | func Igcdex(a *big.Int, b *big.Int) (*big.Int, *big.Int, *big.Int) { 77 | zero := big.NewInt(0) 78 | one := big.NewInt(1) 79 | switch true { 80 | case a.Cmp(zero) == 0 && b.Cmp(zero) == 0: 81 | return zero, one, zero 82 | case a.Cmp(zero) == 0: 83 | return zero, big.NewInt(int64(a.Sign())), new(big.Int).Abs(b) 84 | case b.Cmp(zero) == 0: 85 | return big.NewInt(int64(a.Sign())), zero, new(big.Int).Abs(a) 86 | default: 87 | xSign := big.NewInt(int64(a.Sign())) 88 | ySign := big.NewInt(int64(b.Sign())) 89 | a = new(big.Int).Abs(a) 90 | b = new(big.Int).Abs(b) 91 | x, y, r, s := big.NewInt(1), big.NewInt(0), big.NewInt(0), big.NewInt(1) 92 | for b.Cmp(zero) != 0 { 93 | q, c := new(big.Int).DivMod(a, b, new(big.Int)) 94 | x = new(big.Int).Sub(x, new(big.Int).Mul(q, r)) 95 | y = new(big.Int).Sub(y, new(big.Int).Mul(q, s)) 96 | 97 | a, b, r, s, x, y = b, c, x, y, r, s 98 | } 99 | 100 | return new(big.Int).Mul(x, xSign), new(big.Int).Mul(y, ySign), a 101 | 102 | } 103 | } 104 | 105 | func IsEven(n *big.Int) bool { 106 | res := new(big.Int).And(n, big.NewInt(1)) 107 | return res.Cmp(big.NewInt(0)) != 0 108 | } 109 | 110 | func ISqrt(x *big.Int) (*big.Int, error) { 111 | if x.Sign() == -1 { 112 | return nil, errors.Errorf("Expected x: %s to be non-negative", x) 113 | } 114 | res := new(big.Int) 115 | return res.Sqrt(x), nil 116 | } 117 | -------------------------------------------------------------------------------- /pkg/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 5 | . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 6 | 7 | "github.com/pkg/errors" 8 | ) 9 | 10 | func IsSubsequence[T comparable](subsequence []T, sequence []T) bool { 11 | startSeqIdx := 0 12 | for _, subElem := range subsequence { 13 | found := false 14 | for idx, elem := range sequence[startSeqIdx:] { 15 | if subElem == elem { 16 | startSeqIdx = idx + 1 17 | found = true 18 | break 19 | } 20 | } 21 | if !found { 22 | return false 23 | } 24 | } 25 | return true 26 | } 27 | 28 | func CheckBuiltinsSubsequence(programBuiltins []string) error { 29 | orderedBuiltinNames := []string{ 30 | "output", 31 | "pedersen", 32 | "range_check", 33 | "ecdsa", 34 | "bitwise", 35 | "ec_op", 36 | "keccak", 37 | "poseidon", 38 | } 39 | if !IsSubsequence(programBuiltins, orderedBuiltinNames) { 40 | return errors.Errorf("program builtins are not in appropiate order") 41 | } 42 | return nil 43 | } 44 | 45 | // Creates a new MaybeRelocatable from a uint64 value 46 | func NewMaybeRelocatableFeltFromUint64(val uint64) *MaybeRelocatable { 47 | return NewMaybeRelocatableFelt(FeltFromUint64(val)) 48 | } 49 | 50 | func NewMaybeRelocatableRelocatableParams(segment_idx int, offset uint) *MaybeRelocatable { 51 | return NewMaybeRelocatableRelocatable(NewRelocatable(segment_idx, offset)) 52 | } 53 | 54 | func AddNSegments(segments MemorySegmentManager, nSegments int) MemorySegmentManager { 55 | for i := 0; i < nSegments; i++ { 56 | segments.AddSegment() 57 | } 58 | return segments 59 | } 60 | -------------------------------------------------------------------------------- /pkg/utils/utils_test.go: -------------------------------------------------------------------------------- 1 | package utils_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/lambdaclass/cairo-vm.go/pkg/utils" 7 | ) 8 | 9 | func TestIsSubsequenceWorks(t *testing.T) { 10 | orderedBuiltinNames := []string{ 11 | "output_builtin", 12 | "pedersen_builtin", 13 | "range_check_builtin", 14 | "ecdsa_builtin", 15 | "bitwise_builtin", 16 | "ec_op_builtin", 17 | "keccak_builtin", 18 | "poseidon_builtin", 19 | } 20 | 21 | subSequence := []string{ 22 | "output_builtin", 23 | "poseidon_builtin", 24 | } 25 | 26 | result := utils.IsSubsequence(subSequence, orderedBuiltinNames) 27 | 28 | if !result { 29 | t.Errorf("The result of IsSubsequence should be true") 30 | } 31 | } 32 | 33 | func TestIsSubsequenceReturnsFalse(t *testing.T) { 34 | orderedBuiltinNames := []string{ 35 | "output_builtin", 36 | "pedersen_builtin", 37 | "range_check_builtin", 38 | "ecdsa_builtin", 39 | "bitwise_builtin", 40 | "ec_op_builtin", 41 | "keccak_builtin", 42 | "poseidon_builtin", 43 | } 44 | 45 | subSequence := []string{ 46 | "poseidon_builtin", 47 | "output_builtin", 48 | } 49 | 50 | result := utils.IsSubsequence(subSequence, orderedBuiltinNames) 51 | 52 | if result { 53 | t.Errorf("The result of IsSubsequence should be false") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/vm/hint_processor_interface.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 5 | "github.com/lambdaclass/cairo-vm.go/pkg/parser" 6 | "github.com/lambdaclass/cairo-vm.go/pkg/types" 7 | ) 8 | 9 | type HintProcessor interface { 10 | // Transforms hint data outputed by the VM into whichever format will be later used by ExecuteHint 11 | CompileHint(hintParams *parser.HintParams, referenceManager *parser.ReferenceManager) (any, error) 12 | // Executes the hint which's data is provided by a dynamic structure previously created by CompileHint 13 | ExecuteHint(vm *VirtualMachine, hintData *any, constants *map[string]lambdaworks.Felt, execScopes *types.ExecutionScopes) error 14 | } 15 | -------------------------------------------------------------------------------- /pkg/vm/memory/relocatable_err.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | type SubReloctableError struct { 4 | Msg string 5 | } 6 | 7 | func (e *SubReloctableError) Error() string { 8 | return e.Msg 9 | } 10 | -------------------------------------------------------------------------------- /pkg/vm/program.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 5 | "github.com/lambdaclass/cairo-vm.go/pkg/parser" 6 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 7 | ) 8 | 9 | type Identifier struct { 10 | FullName string 11 | Members map[string]any 12 | Size int 13 | Decorators []string 14 | PC int 15 | Type string 16 | CairoType string 17 | Value lambdaworks.Felt 18 | Destination string 19 | } 20 | 21 | type Program struct { 22 | Data []memory.MaybeRelocatable 23 | Builtins []string 24 | Identifiers map[string]Identifier 25 | Hints map[uint][]parser.HintParams 26 | ReferenceManager parser.ReferenceManager 27 | Start uint 28 | End uint 29 | } 30 | 31 | func DeserializeProgramJson(compiledProgram parser.CompiledJson) Program { 32 | var program Program 33 | 34 | hexData := compiledProgram.Data 35 | for _, hexVal := range hexData { 36 | felt := lambdaworks.FeltFromHex(hexVal) 37 | program.Data = append(program.Data, *memory.NewMaybeRelocatableFelt(felt)) 38 | } 39 | program.Builtins = compiledProgram.Builtins 40 | program.Identifiers = make(map[string]Identifier) 41 | 42 | start := uint(compiledProgram.Identifiers["__main__.__start__"].PC) 43 | end := uint(compiledProgram.Identifiers["__main__.__end__"].PC) 44 | program.Start = start 45 | program.End = end 46 | 47 | for key, identifier := range compiledProgram.Identifiers { 48 | var programIdentifier Identifier 49 | programIdentifier.FullName = identifier.FullName 50 | programIdentifier.Members = identifier.Members 51 | programIdentifier.Size = identifier.Size 52 | programIdentifier.Decorators = identifier.Decorators 53 | programIdentifier.PC = identifier.PC 54 | programIdentifier.Type = identifier.Type 55 | programIdentifier.CairoType = identifier.CairoType 56 | programIdentifier.Value = lambdaworks.FeltFromDecString(identifier.Value.String()) 57 | programIdentifier.Destination = identifier.Destination 58 | program.Identifiers[key] = programIdentifier 59 | } 60 | program.Hints = compiledProgram.Hints 61 | program.ReferenceManager = compiledProgram.ReferenceManager 62 | 63 | return program 64 | } 65 | 66 | func (p *Program) ExtractConstants() map[string]lambdaworks.Felt { 67 | constants := make(map[string]lambdaworks.Felt) 68 | for name, identifier := range p.Identifiers { 69 | switch identifier.Type { 70 | case "const": 71 | constants[name] = identifier.Value 72 | case "alias": 73 | val, ok := searchConstFromAlias(identifier.Destination, &p.Identifiers) 74 | if ok { 75 | constants[name] = val 76 | } 77 | } 78 | } 79 | return constants 80 | } 81 | 82 | func searchConstFromAlias(destination string, identifiers *map[string]Identifier) (lambdaworks.Felt, bool) { 83 | identifier, ok := (*identifiers)[destination] 84 | if ok { 85 | switch identifier.Type { 86 | case "const": 87 | return identifier.Value, true 88 | case "alias": 89 | return searchConstFromAlias(identifier.Destination, identifiers) 90 | } 91 | } 92 | return lambdaworks.Felt{}, false 93 | } 94 | -------------------------------------------------------------------------------- /pkg/vm/program_test.go: -------------------------------------------------------------------------------- 1 | package vm_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 8 | "github.com/lambdaclass/cairo-vm.go/pkg/vm" 9 | ) 10 | 11 | func TestNewProgram(t *testing.T) { 12 | 13 | } 14 | 15 | func TestExtractConstantsEmpty(t *testing.T) { 16 | program := vm.Program{} 17 | expectedConstants := make(map[string]lambdaworks.Felt) 18 | if !reflect.DeepEqual(program.ExtractConstants(), expectedConstants) { 19 | t.Errorf("Wrong Constants, expected %v, got %v", expectedConstants, program.ExtractConstants()) 20 | } 21 | 22 | } 23 | 24 | func TestExtractConstants(t *testing.T) { 25 | program := vm.Program{ 26 | Identifiers: map[string]vm.Identifier{ 27 | "start": { 28 | Value: lambdaworks.FeltFromUint64(4), 29 | Type: "label", 30 | }, 31 | "end": { 32 | Value: lambdaworks.FeltFromUint64(8), 33 | Type: "label", 34 | }, 35 | "A": { 36 | Value: lambdaworks.FeltFromUint64(7), 37 | Type: "const", 38 | }, 39 | "B": { 40 | Value: lambdaworks.FeltFromUint64(17), 41 | Type: "const", 42 | }, 43 | }, 44 | } 45 | expectedConstants := map[string]lambdaworks.Felt{ 46 | "A": lambdaworks.FeltFromUint64(7), 47 | "B": lambdaworks.FeltFromUint64(17), 48 | } 49 | if !reflect.DeepEqual(program.ExtractConstants(), expectedConstants) { 50 | t.Errorf("Wrong Constants, expected %v, got %v", expectedConstants, program.ExtractConstants()) 51 | } 52 | } 53 | 54 | func TestExtractConstantsWithAliasedConstants(t *testing.T) { 55 | program := vm.Program{ 56 | Identifiers: map[string]vm.Identifier{ 57 | "path.A": { 58 | Value: lambdaworks.FeltFromUint64(7), 59 | Type: "const", 60 | }, 61 | "path.b": { 62 | Value: lambdaworks.FeltFromUint64(17), 63 | Type: "label", 64 | }, 65 | "other_path.A": { 66 | Destination: "path.A", 67 | Type: "alias", 68 | }, 69 | "other_path.b": { 70 | Destination: "path.b", 71 | Type: "alias", 72 | }, 73 | }, 74 | } 75 | expectedConstants := map[string]lambdaworks.Felt{ 76 | "path.A": lambdaworks.FeltFromUint64(7), 77 | "other_path.A": lambdaworks.FeltFromUint64(7), 78 | } 79 | if !reflect.DeepEqual(program.ExtractConstants(), expectedConstants) { 80 | t.Errorf("Wrong Constants, expected %v, got %v", expectedConstants, program.ExtractConstants()) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /pkg/vm/run_context.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "errors" 5 | "math" 6 | 7 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 8 | ) 9 | 10 | // RunContext contains the register states of the 11 | // Cairo VM. 12 | type RunContext struct { 13 | Pc memory.Relocatable 14 | Ap memory.Relocatable 15 | Fp memory.Relocatable 16 | } 17 | 18 | func (run_context RunContext) ComputeDstAddr(instruction Instruction) (memory.Relocatable, error) { 19 | var base_addr memory.Relocatable 20 | switch instruction.DstReg { 21 | case AP: 22 | base_addr = run_context.Ap 23 | case FP: 24 | base_addr = run_context.Fp 25 | } 26 | 27 | if instruction.Off0 < 0 { 28 | return base_addr.SubUint(uint(math.Abs(float64(instruction.Off0)))) 29 | } else { 30 | return base_addr.AddUint(uint(instruction.Off0)), nil 31 | } 32 | 33 | } 34 | 35 | func (run_context RunContext) ComputeOp0Addr(instruction Instruction) (memory.Relocatable, error) { 36 | var base_addr memory.Relocatable 37 | switch instruction.Op0Reg { 38 | case AP: 39 | base_addr = run_context.Ap 40 | case FP: 41 | base_addr = run_context.Fp 42 | } 43 | 44 | if instruction.Off1 < 0 { 45 | return base_addr.SubUint(uint(math.Abs(float64(instruction.Off1)))) 46 | } else { 47 | return base_addr.AddUint(uint(instruction.Off1)), nil 48 | } 49 | } 50 | 51 | func (run_context RunContext) ComputeOp1Addr(instruction Instruction, op0 *memory.MaybeRelocatable) (memory.Relocatable, error) { 52 | var base_addr memory.Relocatable 53 | 54 | switch instruction.Op1Addr { 55 | case Op1SrcFP: 56 | base_addr = run_context.Fp 57 | case Op1SrcAP: 58 | base_addr = run_context.Ap 59 | case Op1SrcImm: 60 | if instruction.Off2 == 1 { 61 | base_addr = run_context.Pc 62 | } else { 63 | base_addr = memory.NewRelocatable(0, 0) 64 | return memory.Relocatable{}, &VirtualMachineError{Msg: "UnknownOp0"} 65 | } 66 | case Op1SrcOp0: 67 | if op0 == nil { 68 | return memory.Relocatable{}, errors.New("Unknown Op0") 69 | } 70 | rel, is_rel := op0.GetRelocatable() 71 | if is_rel { 72 | base_addr = rel 73 | } else { 74 | return memory.Relocatable{}, errors.New("AddressNotRelocatable") 75 | } 76 | } 77 | 78 | if instruction.Off2 < 0 { 79 | return base_addr.SubUint(uint(math.Abs(float64(instruction.Off2)))) 80 | } else { 81 | return base_addr.AddUint(uint(instruction.Off2)), nil 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /pkg/vm/run_resources.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | type RunResources struct { 4 | nSteps *uint 5 | } 6 | 7 | func NewRunResources(nSteps uint) RunResources { 8 | return RunResources{nSteps: &nSteps} 9 | } 10 | 11 | func (r *RunResources) Consumed() bool { 12 | return r.nSteps != nil && *r.nSteps == 0 13 | } 14 | 15 | func (r *RunResources) ConsumeStep() { 16 | if r.nSteps != nil && *r.nSteps != 0 { 17 | *r.nSteps-- 18 | } 19 | } 20 | 21 | func (r *RunResources) GetNSteps() *uint { 22 | return r.nSteps 23 | } 24 | -------------------------------------------------------------------------------- /pkg/vm/trace.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" 5 | "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" 6 | ) 7 | 8 | type TraceEntry struct { 9 | Pc memory.Relocatable 10 | Ap memory.Relocatable 11 | Fp memory.Relocatable 12 | } 13 | 14 | type RelocatedTraceEntry struct { 15 | Pc lambdaworks.Felt 16 | Ap lambdaworks.Felt 17 | Fp lambdaworks.Felt 18 | } 19 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ecdsa==0.18.0 2 | bitarray==2.7.3 3 | fastecdsa==2.2.3 4 | sympy==1.11.1 5 | typeguard==2.13.3 6 | cairo-lang==0.11.0 7 | -------------------------------------------------------------------------------- /scripts/compare_vm_state.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | tests_path="../cairo_programs" 4 | exit_code=0 5 | trace=false 6 | memory=false 7 | passed_tests=0 8 | failed_tests=0 9 | 10 | for i in $@; do 11 | case $i in 12 | "trace") trace=true 13 | ;; 14 | "memory") memory=true 15 | ;; 16 | "proof_mode") tests_path="../cairo_programs/proof_programs" 17 | ;; 18 | *) 19 | ;; 20 | esac 21 | done 22 | 23 | files=$(ls $tests_path) 24 | if [ $? != 0 ]; then 25 | exit $? 26 | fi 27 | 28 | for file in $(ls $tests_path | grep .cairo$ | sed -E 's/\.cairo$//'); do 29 | path_file="$tests_path/$file" 30 | 31 | if $trace; then 32 | if ! diff -q $path_file.go.trace $path_file.rs.trace; then 33 | echo "Traces for $file differ" 34 | exit_code=1 35 | failed_tests=$((failed_tests + 1)) 36 | else 37 | passed_tests=$((passed_tests + 1)) 38 | fi 39 | fi 40 | 41 | if $memory; then 42 | if ! python memory_comparator.py $path_file.go.memory $path_file.rs.memory; then 43 | echo "Memory differs for $file" 44 | exit_code=1 45 | failed_tests=$((failed_tests + 1)) 46 | else 47 | passed_tests=$((passed_tests + 1)) 48 | fi 49 | fi 50 | done 51 | 52 | if test $failed_tests = 0; then 53 | echo "All $passed_tests tests passed; no discrepancies found" 54 | else 55 | echo "Comparisons: $failed_tests failed, $passed_tests passed, $((failed_tests + passed_tests)) total" 56 | fi 57 | 58 | exit "${exit_code}" 59 | -------------------------------------------------------------------------------- /scripts/memory_comparator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | def main(): 6 | filename1 = sys.argv[1] 7 | filename2 = sys.argv[2] 8 | cairo_mem = {} 9 | cairo_rs_mem = {} 10 | 11 | with open(filename1, 'rb') as f: 12 | cairo_raw = f.read() 13 | assert len(cairo_raw) % 40 == 0, f'{filename1}: malformed memory file from Cairo VM' 14 | chunks = len(cairo_raw) // 40 15 | for i in range(0, chunks): 16 | chunk = cairo_raw[i*40:(i+1)*40] 17 | k, v = int.from_bytes(chunk[:8], 'little'), int.from_bytes(chunk[8:], 'little') 18 | assert k not in cairo_mem, f'{filename1}: address {k} has two values' 19 | cairo_mem[k] = v 20 | assert len(cairo_mem) * 40 == len(cairo_raw), f'{filename1}: {len(cairo_mem) * 40} != {len(cairo_raw)}' 21 | 22 | with open(filename2, 'rb') as f: 23 | cairo_rs_raw = f.read() 24 | assert len(cairo_rs_raw) % 40 == 0, f'{filename2}: malformed memory file from cairo-vm' 25 | chunks = len(cairo_rs_raw) // 40 26 | for i in range(0, chunks): 27 | chunk = cairo_rs_raw[i*40:(i+1)*40] 28 | k, v = int.from_bytes(chunk[:8], 'little'), int.from_bytes(chunk[8:], 'little') 29 | assert k not in cairo_rs_mem, f'{filename2}: address {k} has two values' 30 | cairo_rs_mem[k] = v 31 | assert len(cairo_rs_mem) * 40 == len(cairo_rs_raw), f'{filename2}: {len(cairo_rs_mem) * 40} != {len(cairo_rs_raw)}' 32 | 33 | assert len(cairo_mem) == len(cairo_rs_mem), f'{filename2}: len(cairo_mem)={len(cairo_mem)} len(cairo_mem)={len(cairo_rs_mem)}' 34 | if cairo_mem != cairo_rs_mem: 35 | print(f'Mismatch between {filename1} (Cairo) and {filename2} (cairo_rs)') 36 | print('keys in Cairo but not cairo-vm:') 37 | for k in cairo_mem: 38 | if k in cairo_rs_mem: 39 | continue 40 | print(f'{k}:{v}') 41 | print('keys in cairo_rs but not Cairo:') 42 | for k in cairo_rs_mem: 43 | if k in cairo_mem: 44 | continue 45 | print(f'{k}:{v}') 46 | print('mismatched values (Cairo <-> cairo_rs)):') 47 | for k in cairo_rs_mem: 48 | if k not in cairo_mem: 49 | continue 50 | if cairo_rs_mem[k] == cairo_mem[k]: 51 | continue 52 | print(f'{k}:({cairo_mem[k]} <-> {cairo_rs_mem[k]})') 53 | exit(1) 54 | 55 | 56 | if __name__ == '__main__': 57 | main() 58 | --------------------------------------------------------------------------------