diff --git a/.github/codecov.yml b/.github/codecov.yml index 0af02dda21..50fe74a541 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -7,4 +7,5 @@ coverage: ignore: - src/vm/errors - src/types/errors + - hint_accountant - ./deps diff --git a/.github/workflows/hint_accountant.yml b/.github/workflows/hint_accountant.yml new file mode 100644 index 0000000000..87ea94c036 --- /dev/null +++ b/.github/workflows/hint_accountant.yml @@ -0,0 +1,28 @@ +name: Update missing hints tracking issue + +on: + push: + branches: [ main ] + +env: + CARGO_TERM_COLOR: always + +jobs: + run: + runs-on: ubuntu-22.04 + steps: + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@1.66.1 + - name: Set up Cargo cache + uses: Swatinem/rust-cache@v2 + - name: Checkout + uses: actions/checkout@v3 + - name: Run the hint accounting script + run: cargo r -p hint_accountant | tee comment.md + - name: Update comment in tracking issue + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: 1031 + comment-id: 1518234161 + body-path: comment.md + edit-mode: replace diff --git a/.gitignore b/.gitignore index 6ce6b063ab..01c4357d9d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ **/.DS_Store **/*.svg **/*.json +!hint_accountant/whitelists/*.json !cairo_programs/manually_compiled/*.json **/*.trace **/*.memory diff --git a/Cargo.lock b/Cargo.lock index f9b54c6a45..5778386a06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -757,6 +757,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hint_accountant" +version = "0.3.0-rc1" +dependencies = [ + "cairo-vm", + "serde", + "serde_json", +] + [[package]] name = "hmac" version = "0.12.1" diff --git a/Cargo.toml b/Cargo.toml index 70b65f0318..3fa3785db3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = [".", "felt", "cairo-vm-cli", "./deps/parse-hyperlinks"] +members = [".", "cairo-vm-cli", "felt", "hint_accountant", "./deps/parse-hyperlinks"] [package] name = "cairo-vm" diff --git a/hint_accountant/Cargo.toml b/hint_accountant/Cargo.toml new file mode 100644 index 0000000000..0ee8d85969 --- /dev/null +++ b/hint_accountant/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "hint_accountant" +version = "0.3.0-rc1" +edition = "2021" +license = "Apache-2.0" +description = "A script to check which whitelisted hints we're missing" + +[dependencies] +cairo-vm = { path = "..", version = "0.3.0-rc1" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/hint_accountant/src/main.rs b/hint_accountant/src/main.rs new file mode 100644 index 0000000000..973c78ef8b --- /dev/null +++ b/hint_accountant/src/main.rs @@ -0,0 +1,90 @@ +#![deny(warnings)] +#![forbid(unsafe_code)] +use cairo_vm::{ + hint_processor::{ + builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor, + hint_processor_definition::HintProcessor, + }, + serde::deserialize_program::ApTracking, + types::exec_scope::ExecutionScopes, + vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}, + with_std::collections::{HashMap, HashSet}, +}; +use serde::Deserialize; +use serde_json; +use serde_json::Value; + +const WHITELISTS: [&'static str; 15] = [ + include_str!("../whitelists/0.10.3.json"), + include_str!("../whitelists/0.6.0.json"), + include_str!("../whitelists/0.8.2.json"), + include_str!("../whitelists/384_bit_prime_field.json"), + include_str!("../whitelists/cairo_blake2s.json"), + include_str!("../whitelists/cairo_keccak.json"), + include_str!("../whitelists/cairo_secp.json"), + include_str!("../whitelists/cairo_sha256.json"), + include_str!("../whitelists/cairo_sha256_arbitrary_input_length.json"), + include_str!("../whitelists/ec_bigint.json"), + include_str!("../whitelists/ec_recover.json"), + include_str!("../whitelists/encode_packed.json"), + include_str!("../whitelists/latest.json"), + include_str!("../whitelists/uint256_improvements.json"), + include_str!("../whitelists/vrf.json"), +]; + +#[derive(Deserialize)] +struct AllowedHintExpression { + #[serde(rename(deserialize = "allowed_expressions"))] + _allowed_expressions: Option, + hint_lines: Vec>, +} + +#[derive(Deserialize)] +struct Whitelist { + #[serde(rename(deserialize = "allowed_reference_expressions_for_hint"))] + allowed_hint_expressions: Vec, +} + +fn run() { + let mut vm = VirtualMachine::new(false); + let mut hint_executor = BuiltinHintProcessor::new_empty(); + let (ap_tracking_data, reference_ids, references, mut exec_scopes, constants) = ( + ApTracking::default(), + HashMap::new(), + HashMap::new(), + ExecutionScopes::new(), + HashMap::new(), + ); + let missing_hints: HashSet<_> = WHITELISTS + .iter() + .flat_map(|wl| { + serde_json::from_str::(wl) + .unwrap() + .allowed_hint_expressions + }) + .map(|ahe| ahe.hint_lines.join("\n")) + .filter(|h| { + let hint_data = hint_executor + .compile_hint(&h, &ap_tracking_data, &reference_ids, &references) + .expect("this implementation is infallible"); + matches!( + hint_executor.execute_hint(&mut vm, &mut exec_scopes, &hint_data, &constants), + Err(HintError::UnknownHint(_)), + ) + }) + .collect(); + + println!("{} missing hints:", missing_hints.len()); + for hint in missing_hints.iter() { + println!(""); + println!("```"); + println!("%{{"); + println!("{hint}"); + println!("%}}"); + println!("```"); + } +} + +fn main() { + run() +} diff --git a/hint_accountant/whitelists/0.10.3.json b/hint_accountant/whitelists/0.10.3.json new file mode 100644 index 0000000000..2fd1a7355a --- /dev/null +++ b/hint_accountant/whitelists/0.10.3.json @@ -0,0 +1,978 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "# Add dummy pairs of input and output.", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "_block_size = int(ids.BLOCK_SIZE)", + "assert 0 <= _keccak_state_size_felts < 100", + "assert 0 <= _block_size < 10", + "inp = [0] * _keccak_state_size_felts", + "padding = (inp + keccak_func(inp)) * _block_size", + "segments.write_arg(ids.keccak_ptr_end, padding)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Prepare arguments for dict_new. In particular, the same dictionary values should be copied", + "# to the new (squashed) dictionary.", + "vm_enter_scope({", + " # Make __dict_manager accessible.", + " '__dict_manager': __dict_manager,", + " # Create a copy of the dict, in case it changes in the future.", + " 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),", + "})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Update the DictTracker's current_ptr to point to the end of the squashed dict.", + "__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\", + " ids.squashed_dict_end.address_" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify dict pointer and prev value.", + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "current_value = dict_tracker.data[ids.key]", + "assert current_value == ids.prev_value, \\", + " f'Wrong previous value in dict. Got {ids.prev_value}, expected {current_value}.'", + "", + "# Update value.", + "dict_tracker.data[ids.key] = ids.new_value", + "dict_tracker.current_ptr += ids.DictAccess.SIZE" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify the assumptions on the relationship between 2**250, ADDR_BOUND and PRIME.", + "ADDR_BOUND = ids.ADDR_BOUND % PRIME", + "assert (2**250 < ADDR_BOUND <= 2**251) and (2 * 2**250 < PRIME) and (", + " ADDR_BOUND * 2 > PRIME), \\", + " 'normalize_address() cannot be used with the current constants.'", + "ids.is_small = 1 if ids.addr < ADDR_BOUND else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "a = (ids.a.high << 128) + ids.a.low", + "b = (ids.b.high << 128) + ids.b.low", + "div = (ids.div.high << 128) + ids.div.low", + "quotient, remainder = divmod(a * b, div)", + "", + "ids.quotient_low.low = quotient & ((1 << 128) - 1)", + "ids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1)", + "ids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1)", + "ids.quotient_high.high = quotient >> 384", + "ids.remainder.low = remainder & ((1 << 128) - 1)", + "ids.remainder.high = remainder >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "a = (ids.a.high << 128) + ids.a.low", + "div = (ids.div.high << 128) + ids.div.low", + "quotient, remainder = divmod(a, div)", + "", + "ids.quotient.low = quotient & ((1 << 128) - 1)", + "ids.quotient.high = quotient >> 128", + "ids.remainder.low = remainder & ((1 << 128) - 1)", + "ids.remainder.high = remainder >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "", + "n_elms = ids.n_elms", + "assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + "if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + "for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] >= ids.key:", + " ids.index = i", + " break", + "else:", + " ids.index = n_elms" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "key = ids.key", + "", + "if '__find_element_index' in globals():", + " ids.index = __find_element_index", + " found_key = memory[array_ptr + elm_size * __find_element_index]", + " assert found_key == key, \\", + " f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \\", + " f'expected key {key}, found key: {found_key}.'", + " # Delete __find_element_index to make sure it's not used for the next calls.", + " del __find_element_index", + "else:", + " n_elms = ids.n_elms", + " assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + " if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + " for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] == key:", + " ids.index = i", + " break", + " else:", + " raise ValueError(f'Key {key} was not found.')" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert excluded == 2" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.n_used_accesses == len(access_indices[key])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.value == 0, 'split_int(): value is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(current_access_indices) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'", + "ids.next_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(positions) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "current_access_indices = sorted(access_indices[key])[::-1]", + "current_access_index = current_access_indices.pop()", + "memory[ids.range_check_ptr] = current_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "current_pos = positions.pop()", + "ids.next_item_index = current_pos - last_pos", + "last_pos = current_pos + 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_access_size = ids.DictAccess.SIZE", + "address = ids.dict_accesses.address_", + "assert ids.ptr_diff % dict_access_size == 0, \\", + " 'Accesses array size must be divisible by DictAccess.SIZE'", + "n_accesses = ids.n_accesses", + "if '__squash_dict_max_size' in globals():", + " assert n_accesses <= __squash_dict_max_size, \\", + " f'squash_dict() can only be used with n_accesses<={__squash_dict_max_size}. ' \\", + " f'Got: n_accesses={n_accesses}.'", + "# A map from key to the list of indices accessing it.", + "access_indices = {}", + "for i in range(n_accesses):", + " key = memory[address + dict_access_size * i]", + " access_indices.setdefault(key, []).append(i)", + "# Descending list of keys.", + "keys = sorted(access_indices.keys(), reverse=True)", + "# Are the keys used bigger than range_check bound.", + "ids.big_keys = 1 if keys[0] >= range_check_builtin.bound else 0", + "ids.first_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.dict_ptr.prev_value = dict_tracker.data[ids.key]", + "dict_tracker.data[ids.key] = ids.new_value" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.value = dict_tracker.data[ids.key]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from collections import defaultdict", + "", + "input_ptr = ids.input", + "input_len = int(ids.input_len)", + "if __usort_max_size is not None:", + " assert input_len <= __usort_max_size, (", + " f\"usort() can only be used with input_len<={__usort_max_size}. \"", + " f\"Got: input_len={input_len}.\"", + " )", + "", + "positions_dict = defaultdict(list)", + "for i in range(input_len):", + " val = memory[input_ptr + i]", + " positions_dict[val].append(i)", + "", + "output = sorted(positions_dict.keys())", + "ids.output_len = len(output)", + "ids.output = segments.gen_arg(output)", + "ids.multiplicities = segments.gen_arg([len(positions_dict[k]) for k in output])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from eth_hash.auto import keccak", + "", + "data, length = ids.data, ids.length", + "", + "if '__keccak_max_size' in globals():", + " assert length <= __keccak_max_size, \\", + " f'unsafe_keccak() can only be used with length<={__keccak_max_size}. ' \\", + " f'Got: length={length}.'", + "", + "keccak_input = bytearray()", + "for word_i, byte_i in enumerate(range(0, length, 16)):", + " word = memory[data + word_i]", + " n_bytes = min(16, length - byte_i)", + " assert 0 <= word < 2 ** (8 * n_bytes)", + " keccak_input += word.to_bytes(n_bytes, 'big')", + "", + "hashed = keccak(keccak_input)", + "ids.high = int.from_bytes(hashed[:16], 'big')", + "ids.low = int.from_bytes(hashed[16:32], 'big')" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "assert 0 <= _keccak_state_size_felts < 100", + "", + "output_values = keccak_func(memory.get_range(", + " ids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts))", + "segments.write_arg(ids.keccak_ptr, output_values)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import N, pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "a = pack(ids.a, PRIME)", + "b = pack(ids.b, PRIME)", + "value = res = div_mod(a, b, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P", + "from starkware.python.math_utils import div_mod", + "", + "value = x_inv = div_mod(1, x, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "q, r = divmod(pack(ids.val, PRIME), SECP_P)", + "assert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"", + "ids.q = q % PRIME" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x0 = pack(ids.point0.x, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "value = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "x = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "x_cube_int = pack(ids.x_cube, PRIME) % SECP_P", + "y_square_int = (x_cube_int + ids.BETA) % SECP_P", + "y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P)", + "", + "# We need to decide whether to take y or SECP_P - y.", + "if ids.v % 2 == y % 2:", + " value = y", + "else:", + " value = (-y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "y = pack(ids.point.y, PRIME) % SECP_P", + "# The modulo operation in python always returns a nonnegative number.", + "value = (-y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import ec_double_slope", + "", + "# Compute the slope.", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import line_slope", + "", + "# Compute the slope.", + "x0 = pack(ids.point0.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y1 = pack(ids.point1.y, PRIME)", + "value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import split", + "", + "segments.write_arg(ids.res.address_, split(value))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int", + "", + "# Correctness check.", + "value = as_int(ids.value, PRIME) % PRIME", + "assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'", + "", + "# Calculation for the assertion.", + "ids.high, ids.low = divmod(ids.value, ids.SHIFT)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int, assert_integer", + "", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "", + "assert_integer(ids.bound)", + "assert ids.bound <= range_check_builtin.bound // 2, \\", + " f'bound={hex(ids.bound)} is out of the valid range.'", + "", + "int_value = as_int(ids.value, PRIME)", + "q, ids.r = divmod(int_value, ids.div)", + "", + "assert -ids.bound <= q < ids.bound, \\", + " f'{int_value} / {ids.div} = {q} is out of the range [{-ids.bound}, {ids.bound}).'", + "", + "ids.biased_q = q + ids.bound" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128", + "assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW", + "assert_integer(ids.value)", + "ids.low = ids.value & ((1 << 128) - 1)", + "ids.high = ids.value >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "assert (ids.a % PRIME) < (ids.b % PRIME), \\", + " f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "ids.q, ids.r = divmod(ids.value, ids.div)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.value)", + "assert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import is_positive", + "ids.is_positive = 1 if is_positive(", + " value=ids.value, prime=PRIME, rc_bound=range_check_builtin.bound) else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.lang.vm.relocatable import RelocatableValue", + "both_ints = isinstance(ids.a, int) and isinstance(ids.b, int)", + "both_relocatable = (", + " isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and", + " ids.a.segment_index == ids.b.segment_index)", + "assert both_ints or both_relocatable, \\", + " f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'", + "assert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME", + "from starkware.python.math_utils import random_ec_point", + "from starkware.python.utils import to_bytes", + "", + "# Define a seed for random_ec_point that's dependent on all the input, so that:", + "# (1) The added point s is deterministic.", + "# (2) It's hard to choose inputs for which the builtin will fail.", + "seed = b\"\".join(map(to_bytes, [ids.p.x, ids.p.y, ids.m, ids.q.x, ids.q.y]))", + "ids.s.x, ids.s.y = random_ec_point(FIELD_PRIME, ALPHA, BETA, seed)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME", + "from starkware.python.math_utils import random_ec_point", + "from starkware.python.utils import to_bytes", + "", + "n_elms = ids.len", + "assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for len. Got: {n_elms}.'", + "if '__chained_ec_op_max_len' in globals():", + " assert n_elms <= __chained_ec_op_max_len, \\", + " f'chained_ec_op() can only be used with len<={__chained_ec_op_max_len}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + "# Define a seed for random_ec_point that's dependent on all the input, so that:", + "# (1) The added point s is deterministic.", + "# (2) It's hard to choose inputs for which the builtin will fail.", + "seed = b\"\".join(", + " map(", + " to_bytes,", + " [", + " ids.p.x,", + " ids.p.y,", + " *memory.get_range(ids.m, n_elms),", + " *memory.get_range(ids.q.address_, 2 * n_elms),", + " ],", + " )", + ")", + "ids.s.x, ids.s.y = random_ec_point(FIELD_PRIME, ALPHA, BETA, seed)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME", + "from starkware.python.math_utils import recover_y", + "ids.p.x = ids.x", + "# This raises an exception if `x` is not on the curve.", + "ids.p.y = recover_y(ids.x, ALPHA, BETA, FIELD_PRIME)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import FIELD_PRIME", + "from starkware.python.math_utils import div_mod, is_quad_residue, sqrt", + "", + "x = ids.x", + "if is_quad_residue(x, FIELD_PRIME):", + " ids.y = sqrt(x, FIELD_PRIME)", + "else:", + " ids.y = sqrt(div_mod(x, 3, FIELD_PRIME), FIELD_PRIME)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "n = (ids.n.high << 128) + ids.n.low", + "root = isqrt(n)", + "assert 0 <= root < 2 ** 128", + "ids.root.low = root", + "ids.root.high = 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "value = ids.value % PRIME", + "assert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"", + "assert 2 ** 250 < PRIME", + "ids.root = isqrt(value)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.is_250 = 1 if ids.addr < 2**250 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.loop_temps.should_continue = 1 if current_access_indices else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = (ids.x.d0 + ids.x.d1 * ids.BASE) & ((1 << 128) - 1)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = ids.a & ((1<<64) - 1)", + "ids.high = ids.a >> 64" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.should_skip_loop = 0 if current_access_indices else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_dict(segments, initial_dict)", + "del initial_dict" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "import itertools", + "", + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "a = ids.a % PRIME", + "b = ids.b % PRIME", + "assert a <= b, f'a = {a} is not less than or equal to b = {b}.'", + "", + "# Find an arc less than PRIME / 3, and another less than PRIME / 2.", + "lengths_and_indices = [(a, 0), (b - a, 1), (PRIME - 1 - b, 2)]", + "lengths_and_indices.sort()", + "assert lengths_and_indices[0][0] <= PRIME // 3 and lengths_and_indices[1][0] <= PRIME // 2", + "excluded = lengths_and_indices[2][1]", + "", + "memory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = (", + " divmod(lengths_and_indices[0][0], ids.PRIME_OVER_3_HIGH))", + "memory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = (", + " divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "last_pos = 0", + "positions = positions_dict[ids.value][::-1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = (ids.scalar % PRIME) % 2" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if excluded != 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if excluded != 1 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = segments.add()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(ids.n_bytes < ids.BYTES_IN_WORD)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(ids.n_bytes >= ids.KECCAK_FULL_RATE_IN_BYTES)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(x == 0)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base", + "assert res < ids.bound, f'split_int(): Limb {res} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_copying = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_loop = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "new_access_index = current_access_indices.pop()", + "ids.loop_temps.index_delta_minus1 = new_access_index - current_access_index - 1", + "current_access_index = new_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "segments.write_arg(ids.inputs, [ids.low % 2 ** 64, ids.low // 2 ** 64])", + "segments.write_arg(ids.inputs + 2, [ids.high % 2 ** 64, ids.high // 2 ** 64])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "sum_low = ids.a.low + ids.b.low", + "ids.carry_low = 1 if sum_low >= ids.SHIFT else 0", + "sum_high = ids.a.high + ids.b.high + ids.carry_low", + "ids.carry_high = 1 if sum_high >= ids.SHIFT else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.deploy(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.emit_event(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_block_number(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_block_timestamp(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_sequencer_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_tx_signature(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.library_call(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.library_call_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.send_message_to_l1(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = k = safe_div(res * b - a, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x - new_x) - y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x0 - new_x) - y0) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope(dict(__usort_max_size = globals().get('__usort_max_size')))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.len})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.n})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_exit_scope()" + ] + } + ] +} diff --git a/hint_accountant/whitelists/0.6.0.json b/hint_accountant/whitelists/0.6.0.json new file mode 100644 index 0000000000..eb0037b686 --- /dev/null +++ b/hint_accountant/whitelists/0.6.0.json @@ -0,0 +1,549 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "# Prepare arguments for dict_new. In particular, the same dictionary values should be copied", + "# to the new (squashed) dictionary.", + "vm_enter_scope({", + " # Make __dict_manager accessible.", + " '__dict_manager': __dict_manager,", + " # Create a copy of the dict, in case it changes in the future.", + " 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),", + "})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Update the DictTracker's current_ptr to point to the end of the squashed dict.", + "__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\", + " ids.squashed_dict_end.address_" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify dict pointer and prev value.", + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "current_value = dict_tracker.data[ids.key]", + "assert current_value == ids.prev_value, \\", + " f'Wrong previous value in dict. Got {ids.prev_value}, expected {current_value}.'", + "", + "# Update value.", + "dict_tracker.data[ids.key] = ids.new_value", + "dict_tracker.current_ptr += ids.DictAccess.SIZE" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify the assumptions on the relationship between 2**250, ADDR_BOUND and PRIME.", + "ADDR_BOUND = ids.ADDR_BOUND % PRIME", + "assert (2**250 < ADDR_BOUND <= 2**251) and (2 * 2**250 < PRIME) and (", + " ADDR_BOUND * 2 > PRIME), \\", + " 'normalize_address() cannot be used with the current constants.'", + "ids.is_small = 1 if ids.addr < ADDR_BOUND else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "a = (ids.a.high << 128) + ids.a.low", + "div = (ids.div.high << 128) + ids.div.low", + "quotient, remainder = divmod(a, div)", + "", + "ids.quotient.low = quotient & ((1 << 128) - 1)", + "ids.quotient.high = quotient >> 128", + "ids.remainder.low = remainder & ((1 << 128) - 1)", + "ids.remainder.high = remainder >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "", + "n_elms = ids.n_elms", + "assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + "if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + "for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] >= ids.key:", + " ids.index = i", + " break", + "else:", + " ids.index = n_elms" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "key = ids.key", + "", + "if '__find_element_index' in globals():", + " ids.index = __find_element_index", + " found_key = memory[array_ptr + elm_size * __find_element_index]", + " assert found_key == key, \\", + " f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \\", + " f'expected key {key}, found key: {found_key}.'", + " # Delete __find_element_index to make sure it's not used for the next calls.", + " del __find_element_index", + "else:", + " n_elms = ids.n_elms", + " assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + " if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + " for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] == key:", + " ids.index = i", + " break", + " else:", + " raise ValueError(f'Key {key} was not found.')" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.n_used_accesses == len(access_indices[key])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.value == 0, 'split_int(): value is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(current_access_indices) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'", + "ids.next_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "current_access_indices = sorted(access_indices[key])[::-1]", + "current_access_index = current_access_indices.pop()", + "memory[ids.range_check_ptr] = current_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_access_size = ids.DictAccess.SIZE", + "address = ids.dict_accesses.address_", + "assert ids.ptr_diff % dict_access_size == 0, \\", + " 'Accesses array size must be divisible by DictAccess.SIZE'", + "n_accesses = ids.n_accesses", + "if '__squash_dict_max_size' in globals():", + " assert n_accesses <= __squash_dict_max_size, \\", + " f'squash_dict() can only be used with n_accesses<={__squash_dict_max_size}. ' \\", + " f'Got: n_accesses={n_accesses}.'", + "# A map from key to the list of indices accessing it.", + "access_indices = {}", + "for i in range(n_accesses):", + " key = memory[address + dict_access_size * i]", + " access_indices.setdefault(key, []).append(i)", + "# Descending list of keys.", + "keys = sorted(access_indices.keys(), reverse=True)", + "# Are the keys used bigger than range_check bound.", + "ids.big_keys = 1 if keys[0] >= range_check_builtin.bound else 0", + "ids.first_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.dict_ptr.prev_value = dict_tracker.data[ids.key]", + "dict_tracker.data[ids.key] = ids.new_value" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.value = dict_tracker.data[ids.key]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from eth_hash.auto import keccak", + "", + "data, length = ids.data, ids.length", + "", + "if '__keccak_max_size' in globals():", + " assert length <= __keccak_max_size, \\", + " f'unsafe_keccak() can only be used with length<={__keccak_max_size}. ' \\", + " f'Got: length={length}.'", + "", + "keccak_input = bytearray()", + "for word_i, byte_i in enumerate(range(0, length, 16)):", + " word = memory[data + word_i]", + " n_bytes = min(16, length - byte_i)", + " assert 0 <= word < 2 ** (8 * n_bytes)", + " keccak_input += word.to_bytes(n_bytes, 'big')", + "", + "hashed = keccak(keccak_input)", + "ids.high = int.from_bytes(hashed[:16], 'big')", + "ids.low = int.from_bytes(hashed[16:32], 'big')" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int", + "", + "# Correctness check.", + "value = as_int(ids.value, PRIME) % PRIME", + "assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'", + "", + "# Calculation for the assertion.", + "ids.high, ids.low = divmod(ids.value, ids.SHIFT)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int, assert_integer", + "", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "", + "assert_integer(ids.bound)", + "assert ids.bound <= range_check_builtin.bound // 2, \\", + " f'bound={hex(ids.bound)} is out of the valid range.'", + "", + "int_value = as_int(ids.value, PRIME)", + "q, ids.r = divmod(int_value, ids.div)", + "", + "assert -ids.bound <= q < ids.bound, \\", + " f'{int_value} / {ids.div} = {q} is out of the range [{-ids.bound}, {ids.bound}).'", + "", + "ids.biased_q = q + ids.bound" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128", + "assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW", + "assert_integer(ids.value)", + "ids.low = ids.value & ((1 << 128) - 1)", + "ids.high = ids.value >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "assert (ids.a % PRIME) < (ids.b % PRIME), \\", + " f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "assert (ids.a % PRIME) <= (ids.b % PRIME), \\", + " f'a = {ids.a % PRIME} is not less than or equal to b = {ids.b % PRIME}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "ids.q, ids.r = divmod(ids.value, ids.div)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.value)", + "assert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import is_positive", + "ids.is_positive = 1 if is_positive(", + " value=ids.value, prime=PRIME, rc_bound=range_check_builtin.bound) else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.lang.vm.relocatable import RelocatableValue", + "both_ints = isinstance(ids.a, int) and isinstance(ids.b, int)", + "both_relocatable = (", + " isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and", + " ids.a.segment_index == ids.b.segment_index)", + "assert both_ints or both_relocatable, \\", + " f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'", + "assert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.a_lsb = ids.a & 1", + "ids.b_lsb = ids.b & 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.is_250 = 1 if ids.addr < 2**250 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.loop_temps.should_continue = 1 if current_access_indices else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = ids.a & ((1<<64) - 1)", + "ids.high = ids.a >> 64" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.should_skip_loop = 0 if current_access_indices else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_dict(segments, initial_dict)", + "del initial_dict" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = segments.add()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base", + "assert res < ids.bound, f'split_int(): Limb {res} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_copying = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_loop = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "new_access_index = current_access_indices.pop()", + "ids.loop_temps.index_delta_minus1 = new_access_index - current_access_index - 1", + "current_access_index = new_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "sum_low = ids.a.low + ids.b.low", + "ids.carry_low = 1 if sum_low >= ids.SHIFT else 0", + "sum_high = ids.a.high + ids.b.high + ids.carry_low", + "ids.carry_high = 1 if sum_high >= ids.SHIFT else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.delegate_call(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_sequencer_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_tx_signature(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.send_message_to_l1(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.len})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.n})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_exit_scope()" + ] + } + ] +} diff --git a/hint_accountant/whitelists/0.8.2.json b/hint_accountant/whitelists/0.8.2.json new file mode 100644 index 0000000000..59dbb70c06 --- /dev/null +++ b/hint_accountant/whitelists/0.8.2.json @@ -0,0 +1,859 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "# Add dummy pairs of input and output.", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "_block_size = int(ids.BLOCK_SIZE)", + "assert 0 <= _keccak_state_size_felts < 100", + "assert 0 <= _block_size < 10", + "inp = [0] * _keccak_state_size_felts", + "padding = (inp + keccak_func(inp)) * _block_size", + "segments.write_arg(ids.keccak_ptr_end, padding)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Prepare arguments for dict_new. In particular, the same dictionary values should be copied", + "# to the new (squashed) dictionary.", + "vm_enter_scope({", + " # Make __dict_manager accessible.", + " '__dict_manager': __dict_manager,", + " # Create a copy of the dict, in case it changes in the future.", + " 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),", + "})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Update the DictTracker's current_ptr to point to the end of the squashed dict.", + "__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\", + " ids.squashed_dict_end.address_" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify dict pointer and prev value.", + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "current_value = dict_tracker.data[ids.key]", + "assert current_value == ids.prev_value, \\", + " f'Wrong previous value in dict. Got {ids.prev_value}, expected {current_value}.'", + "", + "# Update value.", + "dict_tracker.data[ids.key] = ids.new_value", + "dict_tracker.current_ptr += ids.DictAccess.SIZE" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify the assumptions on the relationship between 2**250, ADDR_BOUND and PRIME.", + "ADDR_BOUND = ids.ADDR_BOUND % PRIME", + "assert (2**250 < ADDR_BOUND <= 2**251) and (2 * 2**250 < PRIME) and (", + " ADDR_BOUND * 2 > PRIME), \\", + " 'normalize_address() cannot be used with the current constants.'", + "ids.is_small = 1 if ids.addr < ADDR_BOUND else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "a = (ids.a.high << 128) + ids.a.low", + "div = (ids.div.high << 128) + ids.div.low", + "quotient, remainder = divmod(a, div)", + "", + "ids.quotient.low = quotient & ((1 << 128) - 1)", + "ids.quotient.high = quotient >> 128", + "ids.remainder.low = remainder & ((1 << 128) - 1)", + "ids.remainder.high = remainder >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "", + "n_elms = ids.n_elms", + "assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + "if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + "for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] >= ids.key:", + " ids.index = i", + " break", + "else:", + " ids.index = n_elms" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "key = ids.key", + "", + "if '__find_element_index' in globals():", + " ids.index = __find_element_index", + " found_key = memory[array_ptr + elm_size * __find_element_index]", + " assert found_key == key, \\", + " f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \\", + " f'expected key {key}, found key: {found_key}.'", + " # Delete __find_element_index to make sure it's not used for the next calls.", + " del __find_element_index", + "else:", + " n_elms = ids.n_elms", + " assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + " if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + " for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] == key:", + " ids.index = i", + " break", + " else:", + " raise ValueError(f'Key {key} was not found.')" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.n_used_accesses == len(access_indices[key])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.value == 0, 'split_int(): value is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(current_access_indices) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'", + "ids.next_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(positions) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "current_access_indices = sorted(access_indices[key])[::-1]", + "current_access_index = current_access_indices.pop()", + "memory[ids.range_check_ptr] = current_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "current_pos = positions.pop()", + "ids.next_item_index = current_pos - last_pos", + "last_pos = current_pos + 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_access_size = ids.DictAccess.SIZE", + "address = ids.dict_accesses.address_", + "assert ids.ptr_diff % dict_access_size == 0, \\", + " 'Accesses array size must be divisible by DictAccess.SIZE'", + "n_accesses = ids.n_accesses", + "if '__squash_dict_max_size' in globals():", + " assert n_accesses <= __squash_dict_max_size, \\", + " f'squash_dict() can only be used with n_accesses<={__squash_dict_max_size}. ' \\", + " f'Got: n_accesses={n_accesses}.'", + "# A map from key to the list of indices accessing it.", + "access_indices = {}", + "for i in range(n_accesses):", + " key = memory[address + dict_access_size * i]", + " access_indices.setdefault(key, []).append(i)", + "# Descending list of keys.", + "keys = sorted(access_indices.keys(), reverse=True)", + "# Are the keys used bigger than range_check bound.", + "ids.big_keys = 1 if keys[0] >= range_check_builtin.bound else 0", + "ids.first_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.dict_ptr.prev_value = dict_tracker.data[ids.key]", + "dict_tracker.data[ids.key] = ids.new_value" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.value = dict_tracker.data[ids.key]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from collections import defaultdict", + "", + "input_ptr = ids.input", + "input_len = int(ids.input_len)", + "if __usort_max_size is not None:", + " assert input_len <= __usort_max_size, (", + " f\"usort() can only be used with input_len<={__usort_max_size}. \"", + " f\"Got: input_len={input_len}.\"", + " )", + "", + "positions_dict = defaultdict(list)", + "for i in range(input_len):", + " val = memory[input_ptr + i]", + " positions_dict[val].append(i)", + "", + "output = sorted(positions_dict.keys())", + "ids.output_len = len(output)", + "ids.output = segments.gen_arg(output)", + "ids.multiplicities = segments.gen_arg([len(positions_dict[k]) for k in output])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from eth_hash.auto import keccak", + "", + "data, length = ids.data, ids.length", + "", + "if '__keccak_max_size' in globals():", + " assert length <= __keccak_max_size, \\", + " f'unsafe_keccak() can only be used with length<={__keccak_max_size}. ' \\", + " f'Got: length={length}.'", + "", + "keccak_input = bytearray()", + "for word_i, byte_i in enumerate(range(0, length, 16)):", + " word = memory[data + word_i]", + " n_bytes = min(16, length - byte_i)", + " assert 0 <= word < 2 ** (8 * n_bytes)", + " keccak_input += word.to_bytes(n_bytes, 'big')", + "", + "hashed = keccak(keccak_input)", + "ids.high = int.from_bytes(hashed[:16], 'big')", + "ids.low = int.from_bytes(hashed[16:32], 'big')" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "assert 0 <= _keccak_state_size_felts < 100", + "", + "output_values = keccak_func(memory.get_range(", + " ids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts))", + "segments.write_arg(ids.keccak_ptr, output_values)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import N, pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "a = pack(ids.a, PRIME)", + "b = pack(ids.b, PRIME)", + "value = res = div_mod(a, b, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P", + "from starkware.python.math_utils import div_mod", + "", + "value = x_inv = div_mod(1, x, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "q, r = divmod(pack(ids.val, PRIME), SECP_P)", + "assert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"", + "ids.q = q % PRIME" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x0 = pack(ids.point0.x, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "value = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "x = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "x_cube_int = pack(ids.x_cube, PRIME) % SECP_P", + "y_square_int = (x_cube_int + ids.BETA) % SECP_P", + "y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P)", + "", + "# We need to decide whether to take y or SECP_P - y.", + "if ids.v % 2 == y % 2:", + " value = y", + "else:", + " value = (-y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "y = pack(ids.point.y, PRIME) % SECP_P", + "# The modulo operation in python always returns a nonnegative number.", + "value = (-y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import ec_double_slope", + "", + "# Compute the slope.", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import line_slope", + "", + "# Compute the slope.", + "x0 = pack(ids.point0.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y1 = pack(ids.point1.y, PRIME)", + "value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import split", + "", + "segments.write_arg(ids.res.address_, split(value))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int", + "", + "# Correctness check.", + "value = as_int(ids.value, PRIME) % PRIME", + "assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'", + "", + "# Calculation for the assertion.", + "ids.high, ids.low = divmod(ids.value, ids.SHIFT)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int, assert_integer", + "", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "", + "assert_integer(ids.bound)", + "assert ids.bound <= range_check_builtin.bound // 2, \\", + " f'bound={hex(ids.bound)} is out of the valid range.'", + "", + "int_value = as_int(ids.value, PRIME)", + "q, ids.r = divmod(int_value, ids.div)", + "", + "assert -ids.bound <= q < ids.bound, \\", + " f'{int_value} / {ids.div} = {q} is out of the range [{-ids.bound}, {ids.bound}).'", + "", + "ids.biased_q = q + ids.bound" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128", + "assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW", + "assert_integer(ids.value)", + "ids.low = ids.value & ((1 << 128) - 1)", + "ids.high = ids.value >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "a = ids.a % PRIME", + "b = ids.b % PRIME", + "assert a <= b, f'a = {a} is not less than or equal to b = {b}.'", + "", + "ids.small_inputs = int(", + " a < range_check_builtin.bound and (b - a) < range_check_builtin.bound)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "assert (ids.a % PRIME) < (ids.b % PRIME), \\", + " f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "ids.q, ids.r = divmod(ids.value, ids.div)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.value)", + "assert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import is_positive", + "ids.is_positive = 1 if is_positive(", + " value=ids.value, prime=PRIME, rc_bound=range_check_builtin.bound) else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.lang.vm.relocatable import RelocatableValue", + "both_ints = isinstance(ids.a, int) and isinstance(ids.b, int)", + "both_relocatable = (", + " isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and", + " ids.a.segment_index == ids.b.segment_index)", + "assert both_ints or both_relocatable, \\", + " f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'", + "assert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "n = (ids.n.high << 128) + ids.n.low", + "root = isqrt(n)", + "assert 0 <= root < 2 ** 128", + "ids.root.low = root", + "ids.root.high = 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "value = ids.value % PRIME", + "assert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"", + "assert 2 ** 250 < PRIME", + "ids.root = isqrt(value)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.is_250 = 1 if ids.addr < 2**250 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.loop_temps.should_continue = 1 if current_access_indices else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = (ids.x.d0 + ids.x.d1 * ids.BASE) & ((1 << 128) - 1)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = ids.a & ((1<<64) - 1)", + "ids.high = ids.a >> 64" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.should_skip_loop = 0 if current_access_indices else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_dict(segments, initial_dict)", + "del initial_dict" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "last_pos = 0", + "positions = positions_dict[ids.value][::-1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = (ids.scalar % PRIME) % 2" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = segments.add()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(ids.n_bytes < ids.BYTES_IN_WORD)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(ids.n_bytes >= ids.KECCAK_FULL_RATE_IN_BYTES)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(x == 0)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base", + "assert res < ids.bound, f'split_int(): Limb {res} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_copying = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_loop = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "new_access_index = current_access_indices.pop()", + "ids.loop_temps.index_delta_minus1 = new_access_index - current_access_index - 1", + "current_access_index = new_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "segments.write_arg(ids.inputs, [ids.low % 2 ** 64, ids.low // 2 ** 64])", + "segments.write_arg(ids.inputs + 2, [ids.high % 2 ** 64, ids.high // 2 ** 64])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "sum_low = ids.a.low + ids.b.low", + "ids.carry_low = 1 if sum_low >= ids.SHIFT else 0", + "sum_high = ids.a.high + ids.b.high + ids.carry_low", + "ids.carry_high = 1 if sum_high >= ids.SHIFT else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.delegate_call(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.delegate_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.emit_event(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_block_number(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_block_timestamp(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_sequencer_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_tx_signature(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.send_message_to_l1(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = k = safe_div(res * b - a, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x - new_x) - y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x0 - new_x) - y0) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope(dict(__usort_max_size = globals().get('__usort_max_size')))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.len})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.n})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_exit_scope()" + ] + } + ] +} diff --git a/hint_accountant/whitelists/384_bit_prime_field.json b/hint_accountant/whitelists/384_bit_prime_field.json new file mode 100644 index 0000000000..0640c4ddff --- /dev/null +++ b/hint_accountant/whitelists/384_bit_prime_field.json @@ -0,0 +1,223 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "def split(num: int, num_bits_shift: int, length: int):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack(ids.a, num_bits_shift = 128)", + "div = pack(ids.div, num_bits_shift = 128)", + "quotient, remainder = divmod(a, div)", + "", + "quotient_split = split(quotient, num_bits_shift=128, length=3)", + "assert len(quotient_split) == 3", + "", + "ids.quotient.d0 = quotient_split[0]", + "ids.quotient.d1 = quotient_split[1]", + "ids.quotient.d2 = quotient_split[2]", + "", + "remainder_split = split(remainder, num_bits_shift=128, length=3)", + "ids.remainder.d0 = remainder_split[0]", + "ids.remainder.d1 = remainder_split[1]", + "ids.remainder.d2 = remainder_split[2]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "def split(num: int, num_bits_shift: int, length: int):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack(ids.a, num_bits_shift = 128)", + "b = pack(ids.b, num_bits_shift = 128)", + "p = pack(ids.p, num_bits_shift = 128)", + "", + "res = (a - b) % p", + "", + "", + "res_split = split(res, num_bits_shift=128, length=3)", + "", + "ids.res.d0 = res_split[0]", + "ids.res.d1 = res_split[1]", + "ids.res.d2 = res_split[2]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import div_mod", + "", + "def split(num: int, num_bits_shift: int, length: int):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack(ids.a, num_bits_shift = 128)", + "b = pack(ids.b, num_bits_shift = 128)", + "p = pack(ids.p, num_bits_shift = 128)", + "# For python3.8 and above the modular inverse can be computed as follows:", + "# b_inverse_mod_p = pow(b, -1, p)", + "# Instead we use the python3.7-friendly function div_mod from starkware.python.math_utils", + "b_inverse_mod_p = div_mod(1, b, p)", + "", + "", + "b_inverse_mod_p_split = split(b_inverse_mod_p, num_bits_shift=128, length=3)", + "", + "ids.b_inverse_mod_p.d0 = b_inverse_mod_p_split[0]", + "ids.b_inverse_mod_p.d1 = b_inverse_mod_p_split[1]", + "ids.b_inverse_mod_p.d2 = b_inverse_mod_p_split[2]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "def split(num: int, num_bits_shift: int, length: int):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift ", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + " ", + "def pack_extended(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack_extended(ids.a, num_bits_shift = 128)", + "div = pack(ids.div, num_bits_shift = 128)", + "", + "quotient, remainder = divmod(a, div)", + "", + "quotient_split = split(quotient, num_bits_shift=128, length=6)", + "", + "ids.quotient.d0 = quotient_split[0]", + "ids.quotient.d1 = quotient_split[1]", + "ids.quotient.d2 = quotient_split[2]", + "ids.quotient.d3 = quotient_split[3]", + "ids.quotient.d4 = quotient_split[4]", + "ids.quotient.d5 = quotient_split[5]", + "", + "remainder_split = split(remainder, num_bits_shift=128, length=3)", + "ids.remainder.d0 = remainder_split[0]", + "ids.remainder.d1 = remainder_split[1]", + "ids.remainder.d2 = remainder_split[2]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "", + "def split(num: int, num_bits_shift: int, length: int):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack(ids.a, num_bits_shift=128)", + "root = isqrt(a)", + "assert 0 <= root < 2 ** 192", + "root_split = split(root, num_bits_shift=128, length=3)", + "ids.root.d0 = root_split[0]", + "ids.root.d1 = root_split[1]", + "ids.root.d2 = root_split[2]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "sum_d0 = ids.a.d0 + ids.b.d0", + "ids.carry_d0 = 1 if sum_d0 >= ids.SHIFT else 0", + "sum_d1 = ids.a.d1 + ids.b.d1 + ids.carry_d0", + "ids.carry_d1 = 1 if sum_d1 >= ids.SHIFT else 0", + "sum_d2 = ids.a.d2 + ids.b.d2 + ids.carry_d1", + "ids.carry_d2 = 1 if sum_d2 >= ids.SHIFT else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import is_quad_residue, sqrt", + "", + "def split(num: int, num_bits_shift: int = 128, length: int = 3):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int = 128) -> int:", + " limbs = (z.d0, z.d1, z.d2)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "", + "generator = pack(ids.generator)", + "x = pack(ids.x)", + "p = pack(ids.p)", + "", + "success_x = is_quad_residue(x, p)", + "root_x = sqrt(x, p) if success_x else None", + "", + "success_gx = is_quad_residue(generator*x, p)", + "root_gx = sqrt(generator*x, p) if success_gx else None", + "", + "# Check that one is 0 and the other is 1", + "if x != 0:", + " assert success_x + success_gx ==1", + "", + "# `None` means that no root was found, but we need to transform these into a felt no matter what", + "if root_x == None:", + " root_x = 0", + "if root_gx == None:", + " root_gx = 0", + "ids.success_x = int(success_x)", + "ids.success_gx = int(success_gx)", + "split_root_x = split(root_x)", + "split_root_gx = split(root_gx)", + "ids.sqrt_x.d0 = split_root_x[0]", + "ids.sqrt_x.d1 = split_root_x[1]", + "ids.sqrt_x.d2 = split_root_x[2]", + "ids.sqrt_gx.d0 = split_root_gx[0]", + "ids.sqrt_gx.d1 = split_root_gx[1]", + "ids.sqrt_gx.d2 = split_root_gx[2]" + ] + } + ] +} diff --git a/hint_accountant/whitelists/cairo_blake2s.json b/hint_accountant/whitelists/cairo_blake2s.json new file mode 100644 index 0000000000..c17a722a3a --- /dev/null +++ b/hint_accountant/whitelists/cairo_blake2s.json @@ -0,0 +1,134 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [ + { + "expr": "[cast(ap + (-2), felt*)]", + "name": "blake2s.finalize_blake2s.__fp__" + }, + { + "expr": "[cast(fp + (-5), starkware.cairo.common.cairo_builtins.BitwiseBuiltin**)]", + "name": "blake2s.finalize_blake2s.bitwise_ptr" + }, + { + "expr": "[cast(fp + (-3), felt**)]", + "name": "blake2s.finalize_blake2s.blake2s_ptr_end" + }, + { + "expr": "[cast(fp + (-4), felt**)]", + "name": "blake2s.finalize_blake2s.blake2s_ptr_start" + }, + { + "expr": "[cast(ap + (-1), felt*)]", + "name": "blake2s.finalize_blake2s.n" + }, + { + "expr": "[cast(fp + (-6), felt*)]", + "name": "blake2s.finalize_blake2s.range_check_ptr" + }, + { + "expr": "[cast(ap + (-1), felt**)]", + "name": "blake2s.finalize_blake2s.sigma" + } + ], + "hint_lines": [ + "# Add dummy pairs of input and output.", + "from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress", + "", + "_n_packed_instances = int(ids.N_PACKED_INSTANCES)", + "assert 0 <= _n_packed_instances < 20", + "_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)", + "assert 0 <= _blake2s_input_chunk_size_felts < 100", + "", + "message = [0] * _blake2s_input_chunk_size_felts", + "modified_iv = [IV[0] ^ 0x01010020] + IV[1:]", + "output = blake2s_compress(", + " message=message,", + " h=modified_iv,", + " t0=0,", + " t1=0,", + " f0=0xffffffff,", + " f1=0,", + ")", + "padding = (message + modified_iv + [0, 0xffffffff] + output) * (_n_packed_instances - 1)", + "segments.write_arg(ids.blake2s_ptr_end, padding)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "cast([ap + (-10)] + 10, felt*)", + "name": "blake2s.blake2s.blake2s_ptr" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "blake2s.blake2s.blake2s_start" + }, + { + "expr": "[cast(fp + (-4), felt**)]", + "name": "blake2s.blake2s.input" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "blake2s.blake2s.n_bytes" + }, + { + "expr": "cast([ap + (-10)] + 10, felt*)", + "name": "blake2s.blake2s.output" + }, + { + "expr": "[cast(ap + (-2), felt*)]", + "name": "blake2s.blake2s.range_check_ptr" + } + ], + "hint_lines": [ + "from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress", + "", + "_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)", + "assert 0 <= _blake2s_input_chunk_size_felts < 100", + "", + "new_state = blake2s_compress(", + " message=memory.get_range(ids.blake2s_start, _blake2s_input_chunk_size_felts),", + " h=[IV[0] ^ 0x01010020] + IV[1:],", + " t0=ids.n_bytes,", + " t1=0,", + " f0=0xffffffff,", + " f1=0,", + ")", + "", + "segments.write_arg(ids.output, new_state)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(fp + (-6), felt**)]", + "name": "blake2s._blake2s_input.blake2s_ptr" + }, + { + "expr": "[cast(fp, felt*)]", + "name": "blake2s._blake2s_input.full_word" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "blake2s._blake2s_input.input" + }, + { + "expr": "[cast(fp + (-4), felt*)]", + "name": "blake2s._blake2s_input.n_bytes" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "blake2s._blake2s_input.n_words" + }, + { + "expr": "[cast(fp + (-7), felt*)]", + "name": "blake2s._blake2s_input.range_check_ptr" + } + ], + "hint_lines": [ + "ids.full_word = int(ids.n_bytes >= 4)" + ] + } + ] +} diff --git a/hint_accountant/whitelists/cairo_keccak.json b/hint_accountant/whitelists/cairo_keccak.json new file mode 100644 index 0000000000..22d9bf310e --- /dev/null +++ b/hint_accountant/whitelists/cairo_keccak.json @@ -0,0 +1,187 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [ + { + "expr": "[cast(fp + (-5), starkware.cairo.common.cairo_builtins.BitwiseBuiltin**)]", + "name": "keccak.finalize_keccak.bitwise_ptr" + }, + { + "expr": "[cast(fp + (-3), felt**)]", + "name": "keccak.finalize_keccak.keccak_ptr_end" + }, + { + "expr": "[cast(fp + (-4), felt**)]", + "name": "keccak.finalize_keccak.keccak_ptr_start" + }, + { + "expr": "[cast(ap + (-1), felt*)]", + "name": "keccak.finalize_keccak.n" + }, + { + "expr": "[cast(fp + (-6), felt*)]", + "name": "keccak.finalize_keccak.range_check_ptr" + } + ], + "hint_lines": [ + "# Add dummy pairs of input and output.", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "_block_size = int(ids.BLOCK_SIZE)", + "assert 0 <= _keccak_state_size_felts < 100", + "assert 0 <= _block_size < 1000", + "inp = [0] * _keccak_state_size_felts", + "padding = (inp + keccak_func(inp)) * _block_size", + "segments.write_arg(ids.keccak_ptr_end, padding)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(fp + (-4), felt**)]", + "name": "keccak.keccak.input" + }, + { + "expr": "cast([ap + (-10)] + 9, felt*)", + "name": "keccak.keccak.keccak_ptr" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "keccak.keccak.keccak_ptr_start" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "keccak.keccak.n_bytes" + }, + { + "expr": "cast([ap + (-10)] + 9, felt*)", + "name": "keccak.keccak.output" + }, + { + "expr": "[cast(ap + (-2), felt*)]", + "name": "keccak.keccak.range_check_ptr" + } + ], + "hint_lines": [ + "from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "assert 0 <= _keccak_state_size_felts < 100", + "output_values = keccak_func(memory.get_range(", + " ids.keccak_ptr_start, _keccak_state_size_felts))", + "segments.write_arg(ids.output, output_values)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(fp, felt*)]", + "name": "keccak._keccak_input.full_word" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "keccak._keccak_input.input" + }, + { + "expr": "[cast(fp + (-6), felt**)]", + "name": "keccak._keccak_input.keccak_ptr" + }, + { + "expr": "[cast(fp + (-4), felt*)]", + "name": "keccak._keccak_input.n_bytes" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "keccak._keccak_input.n_words" + }, + { + "expr": "[cast(fp + (-7), felt*)]", + "name": "keccak._keccak_input.range_check_ptr" + } + ], + "hint_lines": [ + "ids.full_word = int(ids.n_bytes >= 8)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(ap, felt*)]", + "name": "memset.memset.continue_loop" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "memset.memset.dst" + }, + { + "expr": "[cast(ap + (-1), memset.memset.LoopFrame*)]", + "name": "memset.memset.frame" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "memset.memset.n" + }, + { + "expr": "cast(ap + 1, memset.memset.LoopFrame*)", + "name": "memset.memset.next_frame" + }, + { + "expr": "[cast(fp + (-4), felt*)]", + "name": "memset.memset.value" + } + ], + "hint_lines": [ + "n -= 1", + "ids.continue_loop = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "memset.memset.dst" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "memset.memset.n" + }, + { + "expr": "[cast(fp + (-4), felt*)]", + "name": "memset.memset.value" + } + ], + "hint_lines": [ + "vm_enter_scope({'n': ids.n})" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(ap, felt*)]", + "name": "memset.memset.continue_loop" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "memset.memset.dst" + }, + { + "expr": "[cast(ap + (-1), memset.memset.LoopFrame*)]", + "name": "memset.memset.frame" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "memset.memset.n" + }, + { + "expr": "cast(ap + 1, memset.memset.LoopFrame*)", + "name": "memset.memset.next_frame" + }, + { + "expr": "[cast(fp + (-4), felt*)]", + "name": "memset.memset.value" + } + ], + "hint_lines": [ + "vm_exit_scope()" + ] + } + ] +} diff --git a/hint_accountant/whitelists/cairo_secp.json b/hint_accountant/whitelists/cairo_secp.json new file mode 100644 index 0000000000..5524324efe --- /dev/null +++ b/hint_accountant/whitelists/cairo_secp.json @@ -0,0 +1,295 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "ids.quad_bit = (", + " 8 * ((ids.scalar_v >> ids.m) & 1)", + " + 4 * ((ids.scalar_u >> ids.m) & 1)", + " + 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)", + " + ((ids.scalar_u >> (ids.m - 1)) & 1)", + ")" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.len_hi = max(ids.scalar_u.d2.bit_length(), ids.scalar_v.d2.bit_length())-1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.dibit = ((ids.scalar_u >> ids.m) & 1) + 2 * ((ids.scalar_v >> ids.m) & 1)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.python.math_utils import ec_double_slope", + "", + "# Compute the slope.", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.python.math_utils import line_slope", + "", + "# Compute the slope.", + "x0 = pack(ids.point0.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y1 = pack(ids.point1.y, PRIME)", + "value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "", + "slope = pack(ids.slope, PRIME)", + "x0 = pack(ids.point0.x, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "x = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import div_mod", + "", + "value = x_inv = div_mod(1, x, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "a = pack(ids.a, PRIME)", + "b = pack(ids.b, PRIME)", + "value = res = div_mod(a, b, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = k_plus_one = safe_div(res * b - a, N) + 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "", + "q, r = divmod(pack(ids.val, PRIME), SECP_P)", + "assert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"", + "ids.q = q % PRIME" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "", + "slope = pack(ids.slope, PRIME)", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P", + "from starkware.python.math_utils import div_mod", + "", + "value = x_inv = div_mod(1, x, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P", + "q, r = divmod(pack(ids.val, PRIME), SECP_P)", + "assert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"", + "ids.q = q % PRIME" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x = pack(ids.pt.x, PRIME)", + "y = pack(ids.pt.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x0 = pack(ids.pt0.x, PRIME)", + "x1 = pack(ids.pt1.x, PRIME)", + "y0 = pack(ids.pt0.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import div_mod", + "", + "# Compute the slope.", + "x = pack(ids.pt.x, PRIME)", + "y = pack(ids.pt.y, PRIME)", + "value = slope = div_mod(3 * x ** 2, 2 * y, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import div_mod", + "", + "# Compute the slope.", + "x0 = pack(ids.pt0.x, PRIME)", + "y0 = pack(ids.pt0.y, PRIME)", + "x1 = pack(ids.pt1.x, PRIME)", + "y1 = pack(ids.pt1.y, PRIME)", + "value = slope = div_mod(y0 - y1, x0 - x1, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "x = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [ + { + "expr": "cast((10428087374290690730508609, 77371252455330678278691517, 19342813113834066795298815), secp_defs.BigInt3)", + "name": "secp.mul_s_inv.n" + } + ], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "x = pack(ids.x, PRIME) % N", + "s = pack(ids.s, PRIME) % N", + "value = res = div_mod(x, s, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import split", + "segments.write_arg(ids.res.address_, split(value))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.value)", + "assert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = (ids.scalar % PRIME) % 2" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = int(x == 0)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(x == 0)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "cast((10428087374290690730508609, 77371252455330678278691517, 19342813113834066795298815), secp_defs.BigInt3)", + "name": "secp.mul_s_inv.n" + } + ], + "hint_lines": [ + "value = k = safe_div(res * s - x, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x - new_x) - y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x0 - new_x) - y0) % SECP_P" + ] + } + ] +} diff --git a/hint_accountant/whitelists/cairo_sha256.json b/hint_accountant/whitelists/cairo_sha256.json new file mode 100644 index 0000000000..529d99ad8d --- /dev/null +++ b/hint_accountant/whitelists/cairo_sha256.json @@ -0,0 +1,123 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [ + { + "expr": "[cast(ap + (-2), felt*)]", + "name": "sha256.finalize_sha256.__fp__" + }, + { + "expr": "[cast(fp + (-5), starkware.cairo.common.cairo_builtins.BitwiseBuiltin**)]", + "name": "sha256.finalize_sha256.bitwise_ptr" + }, + { + "expr": "[cast(ap + (-1), felt*)]", + "name": "sha256.finalize_sha256.n" + }, + { + "expr": "[cast(fp + (-6), felt*)]", + "name": "sha256.finalize_sha256.range_check_ptr" + }, + { + "expr": "[cast(ap + (-1), felt**)]", + "name": "sha256.finalize_sha256.round_constants" + }, + { + "expr": "[cast(fp + (-3), felt**)]", + "name": "sha256.finalize_sha256.sha256_ptr_end" + }, + { + "expr": "[cast(fp + (-4), felt**)]", + "name": "sha256.finalize_sha256.sha256_ptr_start" + } + ], + "hint_lines": [ + "# Add dummy pairs of input and output.", + "from starkware.cairo.common.cairo_sha256.sha256_utils import (", + " IV, compute_message_schedule, sha2_compress_function)", + "", + "_block_size = int(ids.BLOCK_SIZE)", + "assert 0 <= _block_size < 20", + "_sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS)", + "assert 0 <= _sha256_input_chunk_size_felts < 100", + "", + "message = [0] * _sha256_input_chunk_size_felts", + "w = compute_message_schedule(message)", + "output = sha2_compress_function(IV, w)", + "padding = (message + IV + output) * (_block_size - 1)", + "segments.write_arg(ids.sha256_ptr_end, padding)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(fp + (-4), felt**)]", + "name": "sha256.sha256.input" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "sha256.sha256.n_bytes" + }, + { + "expr": "cast([ap + (-11)] + 10, felt*)", + "name": "sha256.sha256.output" + }, + { + "expr": "[cast(ap + (-2), felt*)]", + "name": "sha256.sha256.range_check_ptr" + }, + { + "expr": "cast([ap + (-11)] + 10, felt*)", + "name": "sha256.sha256.sha256_ptr" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "sha256.sha256.sha256_start" + } + ], + "hint_lines": [ + "from starkware.cairo.common.cairo_sha256.sha256_utils import (", + " IV, compute_message_schedule, sha2_compress_function)", + "", + "_sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS)", + "assert 0 <= _sha256_input_chunk_size_felts < 100", + "", + "w = compute_message_schedule(memory.get_range(", + " ids.sha256_start, _sha256_input_chunk_size_felts))", + "new_state = sha2_compress_function(IV, w)", + "segments.write_arg(ids.output, new_state)" + ] + }, + { + "allowed_expressions": [ + { + "expr": "[cast(fp, felt*)]", + "name": "sha256._sha256_input.full_word" + }, + { + "expr": "[cast(fp + (-5), felt**)]", + "name": "sha256._sha256_input.input" + }, + { + "expr": "[cast(fp + (-4), felt*)]", + "name": "sha256._sha256_input.n_bytes" + }, + { + "expr": "[cast(fp + (-3), felt*)]", + "name": "sha256._sha256_input.n_words" + }, + { + "expr": "[cast(fp + (-7), felt*)]", + "name": "sha256._sha256_input.range_check_ptr" + }, + { + "expr": "[cast(fp + (-6), felt**)]", + "name": "sha256._sha256_input.sha256_ptr" + } + ], + "hint_lines": [ + "ids.full_word = int(ids.n_bytes >= 4)" + ] + } + ] +} diff --git a/hint_accountant/whitelists/cairo_sha256_arbitrary_input_length.json b/hint_accountant/whitelists/cairo_sha256_arbitrary_input_length.json new file mode 100644 index 0000000000..c643a77536 --- /dev/null +++ b/hint_accountant/whitelists/cairo_sha256_arbitrary_input_length.json @@ -0,0 +1,20 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_sha256.sha256_utils import (", + " compute_message_schedule, sha2_compress_function)", + "", + "_sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS)", + "assert 0 <= _sha256_input_chunk_size_felts < 100", + "_sha256_state_size_felts = int(ids.SHA256_STATE_SIZE_FELTS)", + "assert 0 <= _sha256_state_size_felts < 100", + "w = compute_message_schedule(memory.get_range(", + " ids.sha256_start, _sha256_input_chunk_size_felts))", + "new_state = sha2_compress_function(memory.get_range(ids.state, _sha256_state_size_felts), w)", + "segments.write_arg(ids.output, new_state)" + ] + } + ] +} diff --git a/hint_accountant/whitelists/ec_bigint.json b/hint_accountant/whitelists/ec_bigint.json new file mode 100644 index 0000000000..bd479d5323 --- /dev/null +++ b/hint_accountant/whitelists/ec_bigint.json @@ -0,0 +1,33 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.cairo.common.math_utils import as_int", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "p = pack(ids.P, PRIME)", + "x = pack(ids.x, PRIME) + as_int(ids.x.d3, PRIME) * ids.BASE ** 3 + as_int(ids.x.d4, PRIME) * ids.BASE ** 4", + "y = pack(ids.y, PRIME)", + "", + "value = res = div_mod(x, y, p)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import split", + "segments.write_arg(ids.res.address_, split(value))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "k = safe_div(res * y - x, p)", + "value = k if k > 0 else 0 - k", + "ids.flag = 1 if k > 0 else 0" + ] + } + ] +} diff --git a/hint_accountant/whitelists/ec_recover.json b/hint_accountant/whitelists/ec_recover.json new file mode 100644 index 0000000000..def3b57941 --- /dev/null +++ b/hint_accountant/whitelists/ec_recover.json @@ -0,0 +1,48 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "N = pack(ids.n, PRIME)", + "x = pack(ids.x, PRIME) % N", + "s = pack(ids.s, PRIME) % N", + "value = res = div_mod(x, s, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "a = pack(ids.a, PRIME)", + "b = pack(ids.b, PRIME)", + "", + "value = res = a - b" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "a = pack(ids.a, PRIME)", + "b = pack(ids.b, PRIME)", + "product = a * b", + "m = pack(ids.m, PRIME)", + "", + "value = res = product % m" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = k = product // m" + ] + } + ] +} diff --git a/hint_accountant/whitelists/encode_packed.json b/hint_accountant/whitelists/encode_packed.json new file mode 100644 index 0000000000..0ee1c22f33 --- /dev/null +++ b/hint_accountant/whitelists/encode_packed.json @@ -0,0 +1,11 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "x = ids.x", + "ids.bit_length = x.bit_length()" + ] + } + ] +} diff --git a/hint_accountant/whitelists/latest.json b/hint_accountant/whitelists/latest.json new file mode 100644 index 0000000000..cedd734e31 --- /dev/null +++ b/hint_accountant/whitelists/latest.json @@ -0,0 +1,960 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "# Add dummy pairs of input and output.", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "_block_size = int(ids.BLOCK_SIZE)", + "assert 0 <= _keccak_state_size_felts < 100", + "assert 0 <= _block_size < 10", + "inp = [0] * _keccak_state_size_felts", + "padding = (inp + keccak_func(inp)) * _block_size", + "segments.write_arg(ids.keccak_ptr_end, padding)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Prepare arguments for dict_new. In particular, the same dictionary values should be copied", + "# to the new (squashed) dictionary.", + "vm_enter_scope({", + " # Make __dict_manager accessible.", + " '__dict_manager': __dict_manager,", + " # Create a copy of the dict, in case it changes in the future.", + " 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),", + "})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Update the DictTracker's current_ptr to point to the end of the squashed dict.", + "__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\", + " ids.squashed_dict_end.address_" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify dict pointer and prev value.", + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "current_value = dict_tracker.data[ids.key]", + "assert current_value == ids.prev_value, \\", + " f'Wrong previous value in dict. Got {ids.prev_value}, expected {current_value}.'", + "", + "# Update value.", + "dict_tracker.data[ids.key] = ids.new_value", + "dict_tracker.current_ptr += ids.DictAccess.SIZE" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "# Verify the assumptions on the relationship between 2**250, ADDR_BOUND and PRIME.", + "ADDR_BOUND = ids.ADDR_BOUND % PRIME", + "assert (2**250 < ADDR_BOUND <= 2**251) and (2 * 2**250 < PRIME) and (", + " ADDR_BOUND * 2 > PRIME), \\", + " 'normalize_address() cannot be used with the current constants.'", + "ids.is_small = 1 if ids.addr < ADDR_BOUND else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "a = (ids.a.high << 128) + ids.a.low", + "b = (ids.b.high << 128) + ids.b.low", + "div = (ids.div.high << 128) + ids.div.low", + "quotient, remainder = divmod(a * b, div)", + "", + "ids.quotient_low.low = quotient & ((1 << 128) - 1)", + "ids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1)", + "ids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1)", + "ids.quotient_high.high = quotient >> 384", + "ids.remainder.low = remainder & ((1 << 128) - 1)", + "ids.remainder.high = remainder >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "a = (ids.a.high << 128) + ids.a.low", + "div = (ids.div.high << 128) + ids.div.low", + "quotient, remainder = divmod(a, div)", + "", + "ids.quotient.low = quotient & ((1 << 128) - 1)", + "ids.quotient.high = quotient >> 128", + "ids.remainder.low = remainder & ((1 << 128) - 1)", + "ids.remainder.high = remainder >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "", + "n_elms = ids.n_elms", + "assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + "if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + "for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] >= ids.key:", + " ids.index = i", + " break", + "else:", + " ids.index = n_elms" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "array_ptr = ids.array_ptr", + "elm_size = ids.elm_size", + "assert isinstance(elm_size, int) and elm_size > 0, \\", + " f'Invalid value for elm_size. Got: {elm_size}.'", + "key = ids.key", + "", + "if '__find_element_index' in globals():", + " ids.index = __find_element_index", + " found_key = memory[array_ptr + elm_size * __find_element_index]", + " assert found_key == key, \\", + " f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \\", + " f'expected key {key}, found key: {found_key}.'", + " # Delete __find_element_index to make sure it's not used for the next calls.", + " del __find_element_index", + "else:", + " n_elms = ids.n_elms", + " assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for n_elms. Got: {n_elms}.'", + " if '__find_element_max_size' in globals():", + " assert n_elms <= __find_element_max_size, \\", + " f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + " for i in range(n_elms):", + " if memory[array_ptr + elm_size * i] == key:", + " ids.index = i", + " break", + " else:", + " raise ValueError(f'Key {key} was not found.')" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert excluded == 2" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.n_used_accesses == len(access_indices[key])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert ids.value == 0, 'split_int(): value is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(current_access_indices) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'", + "ids.next_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "assert len(positions) == 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "current_access_indices = sorted(access_indices[key])[::-1]", + "current_access_index = current_access_indices.pop()", + "memory[ids.range_check_ptr] = current_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "current_pos = positions.pop()", + "ids.next_item_index = current_pos - last_pos", + "last_pos = current_pos + 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_access_size = ids.DictAccess.SIZE", + "address = ids.dict_accesses.address_", + "assert ids.ptr_diff % dict_access_size == 0, \\", + " 'Accesses array size must be divisible by DictAccess.SIZE'", + "n_accesses = ids.n_accesses", + "if '__squash_dict_max_size' in globals():", + " assert n_accesses <= __squash_dict_max_size, \\", + " f'squash_dict() can only be used with n_accesses<={__squash_dict_max_size}. ' \\", + " f'Got: n_accesses={n_accesses}.'", + "# A map from key to the list of indices accessing it.", + "access_indices = {}", + "for i in range(n_accesses):", + " key = memory[address + dict_access_size * i]", + " access_indices.setdefault(key, []).append(i)", + "# Descending list of keys.", + "keys = sorted(access_indices.keys(), reverse=True)", + "# Are the keys used bigger than range_check bound.", + "ids.big_keys = 1 if keys[0] >= range_check_builtin.bound else 0", + "ids.first_key = key = keys.pop()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.dict_ptr.prev_value = dict_tracker.data[ids.key]", + "dict_tracker.data[ids.key] = ids.new_value" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)", + "dict_tracker.current_ptr += ids.DictAccess.SIZE", + "ids.value = dict_tracker.data[ids.key]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from collections import defaultdict", + "", + "input_ptr = ids.input", + "input_len = int(ids.input_len)", + "if __usort_max_size is not None:", + " assert input_len <= __usort_max_size, (", + " f\"usort() can only be used with input_len<={__usort_max_size}. \"", + " f\"Got: input_len={input_len}.\"", + " )", + "", + "positions_dict = defaultdict(list)", + "for i in range(input_len):", + " val = memory[input_ptr + i]", + " positions_dict[val].append(i)", + "", + "output = sorted(positions_dict.keys())", + "ids.output_len = len(output)", + "ids.output = segments.gen_arg(output)", + "ids.multiplicities = segments.gen_arg([len(positions_dict[k]) for k in output])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.keccak_utils.keccak_utils import keccak_func", + "_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)", + "assert 0 <= _keccak_state_size_felts < 100", + "", + "output_values = keccak_func(memory.get_range(", + " ids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts))", + "segments.write_arg(ids.keccak_ptr, output_values)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import N, pack", + "from starkware.python.math_utils import div_mod, safe_div", + "", + "a = pack(ids.a, PRIME)", + "b = pack(ids.b, PRIME)", + "value = res = div_mod(a, b, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P", + "from starkware.python.math_utils import div_mod", + "", + "value = x_inv = div_mod(1, x, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "q, r = divmod(pack(ids.val, PRIME), SECP_P)", + "assert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"", + "ids.q = q % PRIME" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "slope = pack(ids.slope, PRIME)", + "x0 = pack(ids.point0.x, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "value = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "x = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "x_cube_int = pack(ids.x_cube, PRIME) % SECP_P", + "y_square_int = (x_cube_int + ids.BETA) % SECP_P", + "y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P)", + "", + "# We need to decide whether to take y or SECP_P - y.", + "if ids.v % 2 == y % 2:", + " value = y", + "else:", + " value = (-y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "", + "y = pack(ids.point.y, PRIME) % SECP_P", + "# The modulo operation in python always returns a nonnegative number.", + "value = (-y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import ec_double_slope", + "", + "# Compute the slope.", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack", + "from starkware.python.math_utils import line_slope", + "", + "# Compute the slope.", + "x0 = pack(ids.point0.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y1 = pack(ids.point1.y, PRIME)", + "value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import split", + "", + "segments.write_arg(ids.res.address_, split(value))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int", + "", + "# Correctness check.", + "value = as_int(ids.value, PRIME) % PRIME", + "assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'", + "", + "# Calculation for the assertion.", + "ids.high, ids.low = divmod(ids.value, ids.SHIFT)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import as_int, assert_integer", + "", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "", + "assert_integer(ids.bound)", + "assert ids.bound <= range_check_builtin.bound // 2, \\", + " f'bound={hex(ids.bound)} is out of the valid range.'", + "", + "int_value = as_int(ids.value, PRIME)", + "q, ids.r = divmod(int_value, ids.div)", + "", + "assert -ids.bound <= q < ids.bound, \\", + " f'{int_value} / {ids.div} = {q} is out of the range [{-ids.bound}, {ids.bound}).'", + "", + "ids.biased_q = q + ids.bound" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128", + "assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW", + "assert_integer(ids.value)", + "ids.low = ids.value & ((1 << 128) - 1)", + "ids.high = ids.value >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "assert (ids.a % PRIME) < (ids.b % PRIME), \\", + " f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.div)", + "assert 0 < ids.div <= PRIME // range_check_builtin.bound, \\", + " f'div={hex(ids.div)} is out of the valid range.'", + "ids.q, ids.r = divmod(ids.value, ids.div)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.value)", + "assert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.math_utils import is_positive", + "ids.is_positive = 1 if is_positive(", + " value=ids.value, prime=PRIME, rc_bound=range_check_builtin.bound) else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.lang.vm.relocatable import RelocatableValue", + "both_ints = isinstance(ids.a, int) and isinstance(ids.b, int)", + "both_relocatable = (", + " isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and", + " ids.a.segment_index == ids.b.segment_index)", + "assert both_ints or both_relocatable, \\", + " f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'", + "assert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME", + "from starkware.python.math_utils import random_ec_point", + "from starkware.python.utils import to_bytes", + "", + "# Define a seed for random_ec_point that's dependent on all the input, so that:", + "# (1) The added point s is deterministic.", + "# (2) It's hard to choose inputs for which the builtin will fail.", + "seed = b\"\".join(map(to_bytes, [ids.p.x, ids.p.y, ids.m, ids.q.x, ids.q.y]))", + "ids.s.x, ids.s.y = random_ec_point(FIELD_PRIME, ALPHA, BETA, seed)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME", + "from starkware.python.math_utils import random_ec_point", + "from starkware.python.utils import to_bytes", + "", + "n_elms = ids.len", + "assert isinstance(n_elms, int) and n_elms >= 0, \\", + " f'Invalid value for len. Got: {n_elms}.'", + "if '__chained_ec_op_max_len' in globals():", + " assert n_elms <= __chained_ec_op_max_len, \\", + " f'chained_ec_op() can only be used with len<={__chained_ec_op_max_len}. ' \\", + " f'Got: n_elms={n_elms}.'", + "", + "# Define a seed for random_ec_point that's dependent on all the input, so that:", + "# (1) The added point s is deterministic.", + "# (2) It's hard to choose inputs for which the builtin will fail.", + "seed = b\"\".join(", + " map(", + " to_bytes,", + " [", + " ids.p.x,", + " ids.p.y,", + " *memory.get_range(ids.m, n_elms),", + " *memory.get_range(ids.q.address_, 2 * n_elms),", + " ],", + " )", + ")", + "ids.s.x, ids.s.y = random_ec_point(FIELD_PRIME, ALPHA, BETA, seed)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME", + "from starkware.python.math_utils import recover_y", + "ids.p.x = ids.x", + "# This raises an exception if `x` is not on the curve.", + "ids.p.y = recover_y(ids.x, ALPHA, BETA, FIELD_PRIME)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.crypto.signature.signature import FIELD_PRIME", + "from starkware.python.math_utils import div_mod, is_quad_residue, sqrt", + "", + "x = ids.x", + "if is_quad_residue(x, FIELD_PRIME):", + " ids.y = sqrt(x, FIELD_PRIME)", + "else:", + " ids.y = sqrt(div_mod(x, 3, FIELD_PRIME), FIELD_PRIME)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "n = (ids.n.high << 128) + ids.n.low", + "root = isqrt(n)", + "assert 0 <= root < 2 ** 128", + "ids.root.low = root", + "ids.root.high = 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "value = ids.value % PRIME", + "assert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"", + "assert 2 ** 250 < PRIME", + "ids.root = isqrt(value)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.is_250 = 1 if ids.addr < 2**250 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.loop_temps.should_continue = 1 if current_access_indices else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = (ids.x.d0 + ids.x.d1 * ids.BASE) & ((1 << 128) - 1)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = ids.a & ((1<<64) - 1)", + "ids.high = ids.a >> 64" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.should_skip_loop = 0 if current_access_indices else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "if '__dict_manager' not in globals():", + " from starkware.cairo.common.dict import DictManager", + " __dict_manager = DictManager()", + "", + "memory[ap] = __dict_manager.new_dict(segments, initial_dict)", + "del initial_dict" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "import itertools", + "", + "from starkware.cairo.common.math_utils import assert_integer", + "assert_integer(ids.a)", + "assert_integer(ids.b)", + "a = ids.a % PRIME", + "b = ids.b % PRIME", + "assert a <= b, f'a = {a} is not less than or equal to b = {b}.'", + "", + "# Find an arc less than PRIME / 3, and another less than PRIME / 2.", + "lengths_and_indices = [(a, 0), (b - a, 1), (PRIME - 1 - b, 2)]", + "lengths_and_indices.sort()", + "assert lengths_and_indices[0][0] <= PRIME // 3 and lengths_and_indices[1][0] <= PRIME // 2", + "excluded = lengths_and_indices[2][1]", + "", + "memory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = (", + " divmod(lengths_and_indices[0][0], ids.PRIME_OVER_3_HIGH))", + "memory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = (", + " divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "last_pos = 0", + "positions = positions_dict[ids.value][::-1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = (ids.scalar % PRIME) % 2" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if excluded != 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = 1 if excluded != 1 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = segments.add()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(ids.n_bytes < ids.BYTES_IN_WORD)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(ids.n_bytes >= ids.KECCAK_FULL_RATE_IN_BYTES)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ap] = to_felt_or_relocatable(x == 0)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base", + "assert res < ids.bound, f'split_int(): Limb {res} is out of range.'" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_copying = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "n -= 1", + "ids.continue_loop = 1 if n > 0 else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "new_access_index = current_access_indices.pop()", + "ids.loop_temps.index_delta_minus1 = new_access_index - current_access_index - 1", + "current_access_index = new_access_index" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "segments.write_arg(ids.inputs, [ids.low % 2 ** 64, ids.low // 2 ** 64])", + "segments.write_arg(ids.inputs + 2, [ids.high % 2 ** 64, ids.high // 2 ** 64])" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "sum_low = ids.a.low + ids.b.low", + "ids.carry_low = 1 if sum_low >= ids.SHIFT else 0", + "sum_high = ids.a.high + ids.b.high + ids.carry_low", + "ids.carry_high = 1 if sum_high >= ids.SHIFT else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.deploy(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.emit_event(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_block_number(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_block_timestamp(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_sequencer_address(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.get_tx_signature(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.library_call(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.library_call_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.send_message_to_l1(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.replace_class(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = k = safe_div(res * b - a, N)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x - new_x) - y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "value = new_y = (slope * (x0 - new_x) - y0) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope()" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope(dict(__usort_max_size = globals().get('__usort_max_size')))" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.len})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_enter_scope({'n': ids.n})" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "vm_exit_scope()" + ] + } + ] +} diff --git a/hint_accountant/whitelists/uint256_improvements.json b/hint_accountant/whitelists/uint256_improvements.json new file mode 100644 index 0000000000..7512ac8b28 --- /dev/null +++ b/hint_accountant/whitelists/uint256_improvements.json @@ -0,0 +1,56 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "a = (ids.a.high << 128) + ids.a.low", + "div = (ids.div.b23 << 128) + ids.div.b01", + "quotient, remainder = divmod(a, div)", + "", + "ids.quotient.low = quotient & ((1 << 128) - 1)", + "ids.quotient.high = quotient >> 128", + "ids.remainder.low = remainder & ((1 << 128) - 1)", + "ids.remainder.high = remainder >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "def split(num: int, num_bits_shift: int = 128, length: int = 2):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int = 128) -> int:", + " limbs = (z.low, z.high)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack(ids.a)", + "b = pack(ids.b)", + "res = (a - b)%2**256", + "res_split = split(res)", + "ids.res.low = res_split[0]", + "ids.res.high = res_split[1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import isqrt", + "n = (ids.n.high << 128) + ids.n.low", + "root = isqrt(n)", + "assert 0 <= root < 2 ** 128", + "ids.root = root" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "res = ids.a + ids.b", + "ids.carry = 1 if res >= ids.SHIFT else 0" + ] + } + ] +} diff --git a/hint_accountant/whitelists/vrf.json b/hint_accountant/whitelists/vrf.json new file mode 100644 index 0000000000..66e94506f4 --- /dev/null +++ b/hint_accountant/whitelists/vrf.json @@ -0,0 +1,293 @@ +{ + "allowed_reference_expressions_for_hint": [ + { + "allowed_expressions": [], + "hint_lines": [ + "PRIME = 2**255 - 19", + "II = pow(2, (PRIME - 1) // 4, PRIME)", + "", + "xx = ids.xx.low + (ids.xx.high<<128)", + "x = pow(xx, (PRIME + 3) // 8, PRIME)", + "if (x * x - xx) % PRIME != 0:", + " x = (x * II) % PRIME", + "if x % 2 != 0:", + " x = PRIME - x", + "ids.x.low = x & ((1<<128)-1)", + "ids.x.high = x >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "def split(num: int, num_bits_shift: int, length: int):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.low, z.high)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "def pack_extended(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2, z.d3)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "x = pack_extended(ids.x, num_bits_shift = 128)", + "div = pack(ids.div, num_bits_shift = 128)", + "", + "quotient, remainder = divmod(x, div)", + "", + "quotient_split = split(quotient, num_bits_shift=128, length=4)", + "", + "ids.quotient.d0 = quotient_split[0]", + "ids.quotient.d1 = quotient_split[1]", + "ids.quotient.d2 = quotient_split[2]", + "ids.quotient.d3 = quotient_split[3]", + "", + "remainder_split = split(remainder, num_bits_shift=128, length=2)", + "ids.remainder.low = remainder_split[0]", + "ids.remainder.high = remainder_split[1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "def pack_512(u, num_bits_shift: int) -> int:", + " limbs = (u.d0, u.d1, u.d2, u.d3)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "x = pack_512(ids.x, num_bits_shift = 128)", + "p = ids.p.low + (ids.p.high << 128)", + "x_inverse_mod_p = pow(x,-1, p)", + "", + "x_inverse_mod_p_split = (x_inverse_mod_p & ((1 << 128) - 1), x_inverse_mod_p >> 128)", + "", + "ids.x_inverse_mod_p.low = x_inverse_mod_p_split[0]", + "ids.x_inverse_mod_p.high = x_inverse_mod_p_split[1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import div_mod", + "", + "def split(a: int):", + " return (a & ((1 << 128) - 1), a >> 128)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.low, z.high)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack(ids.a, 128)", + "b = pack(ids.b, 128)", + "p = pack(ids.p, 128)", + "# For python3.8 and above the modular inverse can be computed as follows:", + "# b_inverse_mod_p = pow(b, -1, p)", + "# Instead we use the python3.7-friendly function div_mod from starkware.python.math_utils", + "b_inverse_mod_p = div_mod(1, b, p)", + "", + "b_inverse_mod_p_split = split(b_inverse_mod_p)", + "", + "ids.b_inverse_mod_p.low = b_inverse_mod_p_split[0]", + "ids.b_inverse_mod_p.high = b_inverse_mod_p_split[1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import is_quad_residue, sqrt", + "", + "def split(a: int):", + " return (a & ((1 << 128) - 1), a >> 128)", + "", + "def pack(z) -> int:", + " return z.low + (z.high << 128)", + "", + "generator = pack(ids.generator)", + "x = pack(ids.x)", + "p = pack(ids.p)", + "", + "success_x = is_quad_residue(x, p)", + "root_x = sqrt(x, p) if success_x else None", + "success_gx = is_quad_residue(generator*x, p)", + "root_gx = sqrt(generator*x, p) if success_gx else None", + "", + "# Check that one is 0 and the other is 1", + "if x != 0:", + " assert success_x + success_gx == 1", + "", + "# `None` means that no root was found, but we need to transform these into a felt no matter what", + "if root_x == None:", + " root_x = 0", + "if root_gx == None:", + " root_gx = 0", + "ids.success_x = int(success_x)", + "ids.success_gx = int(success_gx)", + "split_root_x = split(root_x)", + "# print('split root x', split_root_x)", + "split_root_gx = split(root_gx)", + "ids.sqrt_x.low = split_root_x[0]", + "ids.sqrt_x.high = split_root_x[1]", + "ids.sqrt_gx.low = split_root_gx[0]", + "ids.sqrt_gx.high = split_root_gx[1]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "def split(num: int, num_bits_shift: int, length: int):", + " a = []", + " for _ in range(length):", + " a.append( num & ((1 << num_bits_shift) - 1) )", + " num = num >> num_bits_shift", + " return tuple(a)", + "", + "def pack(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "def pack_extended(z, num_bits_shift: int) -> int:", + " limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)", + " return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))", + "", + "a = pack_extended(ids.a, num_bits_shift = 128)", + "div = pack(ids.div, num_bits_shift = 128)", + "", + "quotient, remainder = divmod(a, div)", + "", + "quotient_split = split(quotient, num_bits_shift=128, length=6)", + "", + "ids.quotient.d0 = quotient_split[0]", + "ids.quotient.d1 = quotient_split[1]", + "ids.quotient.d2 = quotient_split[2]", + "ids.quotient.d3 = quotient_split[3]", + "ids.quotient.d4 = quotient_split[4]", + "ids.quotient.d5 = quotient_split[5]", + "", + "remainder_split = split(remainder, num_bits_shift=128, length=3)", + "ids.remainder.d0 = remainder_split[0]", + "ids.remainder.d1 = remainder_split[1]", + "ids.remainder.d2 = remainder_split[2]" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "ids.low = ids.a & ((1<<128) - 1)", + "ids.high = ids.a >> 128" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "sum_low = ids.a.low + ids.b.low", + "ids.carry_low = 1 if sum_low >= ids.SHIFT else 0" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P = 2**255-19", + "to_assert = pack(ids.val, PRIME)", + "q, r = divmod(pack(ids.val, PRIME), SECP_P)", + "assert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"", + "ids.q = q % PRIME" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P=2**255-19", + "", + "x = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P=2**255-19", + "", + "value = pack(ids.x, PRIME) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "SECP_P=2**255-19", + "from starkware.python.math_utils import div_mod", + "", + "value = x_inv = div_mod(1, x, SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P = 2**255-19", + "", + "y = pack(ids.point.y, PRIME) % SECP_P", + "# The modulo operation in python always returns a nonnegative number.", + "value = (-y) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P = 2**255-19", + "", + "slope = pack(ids.slope, PRIME)", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P = 2**255-19", + "", + "slope = pack(ids.slope, PRIME)", + "x0 = pack(ids.point0.x, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "", + "value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import ec_double_slope", + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P = 2**255-19", + "", + "# Compute the slope.", + "x = pack(ids.point.x, PRIME)", + "y = pack(ids.point.y, PRIME)", + "value = slope = ec_double_slope(point=(x, y), alpha=42204101795669822316448953119945047945709099015225996174933988943478124189485, p=SECP_P)" + ] + }, + { + "allowed_expressions": [], + "hint_lines": [ + "from starkware.python.math_utils import line_slope", + "from starkware.cairo.common.cairo_secp.secp_utils import pack", + "SECP_P = 2**255-19", + "# Compute the slope.", + "x0 = pack(ids.point0.x, PRIME)", + "y0 = pack(ids.point0.y, PRIME)", + "x1 = pack(ids.point1.x, PRIME)", + "y1 = pack(ids.point1.y, PRIME)", + "value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)" + ] + } + ] +}