cairo_vm/hint_processor/builtin_hint_processor/
hint_code.rs

1use indoc::indoc;
2
3use crate::define_hint_string_map;
4use crate::stdlib::collections::HashMap;
5
6define_hint_string_map! {
7    HINT_CODES,
8(ADD_SEGMENT, indoc! {r#"memory[ap] = segments.add()"#}),
9(VM_ENTER_SCOPE, indoc! {r#"vm_enter_scope()"#}),
10(VM_EXIT_SCOPE, indoc! {r#"vm_exit_scope()"#}),
11(MEMCPY_ENTER_SCOPE, indoc! {r#"vm_enter_scope({'n': ids.len})"#}),
12(MEMCPY_CONTINUE_COPYING, indoc! {r#"n -= 1
13ids.continue_copying = 1 if n > 0 else 0"#}),
14(MEMSET_ENTER_SCOPE, indoc! {r#"vm_enter_scope({'n': ids.n})"#}),
15(MEMSET_CONTINUE_LOOP, indoc! {r#"n -= 1
16ids.continue_loop = 1 if n > 0 else 0"#}),
17(POW, indoc! {r#"ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1"#}),
18(IS_NN, indoc! {r#"memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1"#}),
19(IS_NN_OUT_OF_RANGE, indoc! {r#"memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1"#}),
20(IS_LE_FELT, indoc! {r#"memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1"#}),
21(IS_POSITIVE, indoc! {r#"from starkware.cairo.common.math_utils import is_positive
22ids.is_positive = 1 if is_positive(
23    value=ids.value, prime=PRIME, rc_bound=range_check_builtin.bound) else 0"#}),
24(ASSERT_NN, indoc! {r#"from starkware.cairo.common.math_utils import assert_integer
25assert_integer(ids.a)
26assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'"#}),
27(ASSERT_NOT_ZERO, indoc! {r#"from starkware.cairo.common.math_utils import assert_integer
28assert_integer(ids.value)
29assert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.'"#}),
30(ASSERT_NOT_EQUAL, indoc! {r#"from starkware.cairo.lang.vm.relocatable import RelocatableValue
31both_ints = isinstance(ids.a, int) and isinstance(ids.b, int)
32both_relocatable = (
33    isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and
34    ids.a.segment_index == ids.b.segment_index)
35assert both_ints or both_relocatable, \
36    f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'
37assert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'"#}),
38(ASSERT_LE_FELT, indoc! {r#"import itertools
39
40from starkware.cairo.common.math_utils import assert_integer
41assert_integer(ids.a)
42assert_integer(ids.b)
43a = ids.a % PRIME
44b = ids.b % PRIME
45assert a <= b, f'a = {a} is not less than or equal to b = {b}.'
46
47# Find an arc less than PRIME / 3, and another less than PRIME / 2.
48lengths_and_indices = [(a, 0), (b - a, 1), (PRIME - 1 - b, 2)]
49lengths_and_indices.sort()
50assert lengths_and_indices[0][0] <= PRIME // 3 and lengths_and_indices[1][0] <= PRIME // 2
51excluded = lengths_and_indices[2][1]
52
53memory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = (
54    divmod(lengths_and_indices[0][0], ids.PRIME_OVER_3_HIGH))
55memory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = (
56    divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))"#}),
57(ASSERT_LE_FELT_V_0_6, "from starkware.cairo.common.math_utils import assert_integer
58assert_integer(ids.a)
59assert_integer(ids.b)
60assert (ids.a % PRIME) <= (ids.b % PRIME), \\
61    f'a = {ids.a % PRIME} is not less than or equal to b = {ids.b % PRIME}.'"),
62(ASSERT_LE_FELT_V_0_8, indoc! {r#"from starkware.cairo.common.math_utils import assert_integer
63assert_integer(ids.a)
64assert_integer(ids.b)
65a = ids.a % PRIME
66b = ids.b % PRIME
67assert a <= b, f'a = {a} is not less than or equal to b = {b}.'
68
69ids.small_inputs = int(
70    a < range_check_builtin.bound and (b - a) < range_check_builtin.bound)"#}),
71(ASSERT_LE_FELT_EXCLUDED_0, indoc! {r#"memory[ap] = 1 if excluded != 0 else 0"#}),
72(ASSERT_LE_FELT_EXCLUDED_1, indoc! {r#"memory[ap] = 1 if excluded != 1 else 0"#}),
73(ASSERT_LE_FELT_EXCLUDED_2, indoc! {r#"assert excluded == 2"#}),
74(ASSERT_LT_FELT, indoc! {r#"from starkware.cairo.common.math_utils import assert_integer
75assert_integer(ids.a)
76assert_integer(ids.b)
77assert (ids.a % PRIME) < (ids.b % PRIME), \
78    f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'"#}),
79(SPLIT_INT_ASSERT_RANGE, indoc! {r#"assert ids.value == 0, 'split_int(): value is out of range.'"#}),
80(ASSERT_250_BITS, indoc! {r#"from starkware.cairo.common.math_utils import as_int
81
82# Correctness check.
83value = as_int(ids.value, PRIME) % PRIME
84assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'
85
86# Calculation for the assertion.
87ids.high, ids.low = divmod(ids.value, ids.SHIFT)"#}),
88(IS_250_BITS, indoc! {r#"ids.is_250 = 1 if ids.addr < 2**250 else 0"#}),
89(IS_ADDR_BOUNDED, indoc! {r#"# Verify the assumptions on the relationship between 2**250, ADDR_BOUND and PRIME.
90ADDR_BOUND = ids.ADDR_BOUND % PRIME
91assert (2**250 < ADDR_BOUND <= 2**251) and (2 * 2**250 < PRIME) and (
92        ADDR_BOUND * 2 > PRIME), \
93    'normalize_address() cannot be used with the current constants.'
94ids.is_small = 1 if ids.addr < ADDR_BOUND else 0"#}),
95(SPLIT_INT, indoc! {r#"memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base
96assert res < ids.bound, f'split_int(): Limb {res} is out of range.'"#}),
97(SPLIT_64, indoc! {r#"ids.low = ids.a & ((1<<64) - 1)
98ids.high = ids.a >> 64"#}),
99(SPLIT_FELT, indoc! {r#"from starkware.cairo.common.math_utils import assert_integer
100assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128
101assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW
102assert_integer(ids.value)
103ids.low = ids.value & ((1 << 128) - 1)
104ids.high = ids.value >> 128"#}),
105(SQRT, indoc! {r#"from starkware.python.math_utils import isqrt
106value = ids.value % PRIME
107assert value < 2 ** 250, f"value={value} is outside of the range [0, 2**250)."
108assert 2 ** 250 < PRIME
109ids.root = isqrt(value)"#}),
110(UNSIGNED_DIV_REM, indoc! {r#"from starkware.cairo.common.math_utils import assert_integer
111assert_integer(ids.div)
112assert 0 < ids.div <= PRIME // range_check_builtin.bound, \
113    f'div={hex(ids.div)} is out of the valid range.'
114ids.q, ids.r = divmod(ids.value, ids.div)"#}),
115(SIGNED_DIV_REM, indoc! {r#"from starkware.cairo.common.math_utils import as_int, assert_integer
116
117assert_integer(ids.div)
118assert 0 < ids.div <= PRIME // range_check_builtin.bound, \
119    f'div={hex(ids.div)} is out of the valid range.'
120
121assert_integer(ids.bound)
122assert ids.bound <= range_check_builtin.bound // 2, \
123    f'bound={hex(ids.bound)} is out of the valid range.'
124
125int_value = as_int(ids.value, PRIME)
126q, ids.r = divmod(int_value, ids.div)
127
128assert -ids.bound <= q < ids.bound, \
129    f'{int_value} / {ids.div} = {q} is out of the range [{-ids.bound}, {ids.bound}).'
130
131ids.biased_q = q + ids.bound"#}),
132(IS_QUAD_RESIDUE, indoc! {r#"from starkware.crypto.signature.signature import FIELD_PRIME
133from starkware.python.math_utils import div_mod, is_quad_residue, sqrt
134
135x = ids.x
136if is_quad_residue(x, FIELD_PRIME):
137    ids.y = sqrt(x, FIELD_PRIME)
138else:
139    ids.y = sqrt(div_mod(x, 3, FIELD_PRIME), FIELD_PRIME)"#}),
140(FIND_ELEMENT, indoc! {r#"array_ptr = ids.array_ptr
141elm_size = ids.elm_size
142assert isinstance(elm_size, int) and elm_size > 0, \
143    f'Invalid value for elm_size. Got: {elm_size}.'
144key = ids.key
145
146if '__find_element_index' in globals():
147    ids.index = __find_element_index
148    found_key = memory[array_ptr + elm_size * __find_element_index]
149    assert found_key == key, \
150        f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \
151        f'expected key {key}, found key: {found_key}.'
152    # Delete __find_element_index to make sure it's not used for the next calls.
153    del __find_element_index
154else:
155    n_elms = ids.n_elms
156    assert isinstance(n_elms, int) and n_elms >= 0, \
157        f'Invalid value for n_elms. Got: {n_elms}.'
158    if '__find_element_max_size' in globals():
159        assert n_elms <= __find_element_max_size, \
160            f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \
161            f'Got: n_elms={n_elms}.'
162
163    for i in range(n_elms):
164        if memory[array_ptr + elm_size * i] == key:
165            ids.index = i
166            break
167    else:
168        raise ValueError(f'Key {key} was not found.')"#}),
169(SEARCH_SORTED_LOWER, indoc! {r#"array_ptr = ids.array_ptr
170elm_size = ids.elm_size
171assert isinstance(elm_size, int) and elm_size > 0, \
172    f'Invalid value for elm_size. Got: {elm_size}.'
173
174n_elms = ids.n_elms
175assert isinstance(n_elms, int) and n_elms >= 0, \
176    f'Invalid value for n_elms. Got: {n_elms}.'
177if '__find_element_max_size' in globals():
178    assert n_elms <= __find_element_max_size, \
179        f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \
180        f'Got: n_elms={n_elms}.'
181
182for i in range(n_elms):
183    if memory[array_ptr + elm_size * i] >= ids.key:
184        ids.index = i
185        break
186else:
187    ids.index = n_elms"#}),
188(SET_ADD, indoc! {r#"assert ids.elm_size > 0
189assert ids.set_ptr <= ids.set_end_ptr
190elm_list = memory.get_range(ids.elm_ptr, ids.elm_size)
191for i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size):
192    if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list:
193        ids.index = i // ids.elm_size
194        ids.is_elm_in_set = 1
195        break
196else:
197    ids.is_elm_in_set = 0"#}),
198(DEFAULT_DICT_NEW, indoc! {r#"if '__dict_manager' not in globals():
199    from starkware.cairo.common.dict import DictManager
200    __dict_manager = DictManager()
201
202memory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)"#}),
203(DICT_NEW, indoc! {r#"if '__dict_manager' not in globals():
204    from starkware.cairo.common.dict import DictManager
205    __dict_manager = DictManager()
206
207memory[ap] = __dict_manager.new_dict(segments, initial_dict)
208del initial_dict"#}),
209(DICT_READ, indoc! {r#"dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)
210dict_tracker.current_ptr += ids.DictAccess.SIZE
211ids.value = dict_tracker.data[ids.key]"#}),
212(DICT_WRITE, indoc! {r#"dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)
213dict_tracker.current_ptr += ids.DictAccess.SIZE
214ids.dict_ptr.prev_value = dict_tracker.data[ids.key]
215dict_tracker.data[ids.key] = ids.new_value"#}),
216(DICT_UPDATE, indoc! {r#"# Verify dict pointer and prev value.
217dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)
218current_value = dict_tracker.data[ids.key]
219assert current_value == ids.prev_value, \
220    f'Wrong previous value in dict. Got {ids.prev_value}, expected {current_value}.'
221
222# Update value.
223dict_tracker.data[ids.key] = ids.new_value
224dict_tracker.current_ptr += ids.DictAccess.SIZE"#}),
225(SQUASH_DICT, indoc! {r#"dict_access_size = ids.DictAccess.SIZE
226address = ids.dict_accesses.address_
227assert ids.ptr_diff % dict_access_size == 0, \
228    'Accesses array size must be divisible by DictAccess.SIZE'
229n_accesses = ids.n_accesses
230if '__squash_dict_max_size' in globals():
231    assert n_accesses <= __squash_dict_max_size, \
232        f'squash_dict() can only be used with n_accesses<={__squash_dict_max_size}. ' \
233        f'Got: n_accesses={n_accesses}.'
234# A map from key to the list of indices accessing it.
235access_indices = {}
236for i in range(n_accesses):
237    key = memory[address + dict_access_size * i]
238    access_indices.setdefault(key, []).append(i)
239# Descending list of keys.
240keys = sorted(access_indices.keys(), reverse=True)
241# Are the keys used bigger than range_check bound.
242ids.big_keys = 1 if keys[0] >= range_check_builtin.bound else 0
243ids.first_key = key = keys.pop()"#}),
244(SQUASH_DICT_INNER_SKIP_LOOP, indoc! {r#"ids.should_skip_loop = 0 if current_access_indices else 1"#}),
245(SQUASH_DICT_INNER_FIRST_ITERATION, indoc! {r#"current_access_indices = sorted(access_indices[key])[::-1]
246current_access_index = current_access_indices.pop()
247memory[ids.range_check_ptr] = current_access_index"#}),
248(SQUASH_DICT_INNER_CHECK_ACCESS_INDEX, indoc! {r#"new_access_index = current_access_indices.pop()
249ids.loop_temps.index_delta_minus1 = new_access_index - current_access_index - 1
250current_access_index = new_access_index"#}),
251(SQUASH_DICT_INNER_CONTINUE_LOOP, indoc! {r#"ids.loop_temps.should_continue = 1 if current_access_indices else 0"#}),
252(SQUASH_DICT_INNER_ASSERT_LEN_KEYS, indoc! {r#"assert len(keys) == 0"#}),
253(SQUASH_DICT_INNER_LEN_ASSERT, indoc! {r#"assert len(current_access_indices) == 0"#}),
254(SQUASH_DICT_INNER_USED_ACCESSES_ASSERT, indoc! {r#"assert ids.n_used_accesses == len(access_indices[key])"#}),
255(SQUASH_DICT_INNER_NEXT_KEY, indoc! {r#"assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'
256ids.next_key = key = keys.pop()"#}),
257(DICT_SQUASH_COPY_DICT, indoc! {r#"# Prepare arguments for dict_new. In particular, the same dictionary values should be copied
258# to the new (squashed) dictionary.
259vm_enter_scope({
260    # Make __dict_manager accessible.
261    '__dict_manager': __dict_manager,
262    # Create a copy of the dict, in case it changes in the future.
263    'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),
264})"#}),
265(DICT_SQUASH_UPDATE_PTR, indoc! {r#"# Update the DictTracker's current_ptr to point to the end of the squashed dict.
266__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \
267    ids.squashed_dict_end.address_"#}),
268(BIGINT_TO_UINT256, indoc! {r#"ids.low = (ids.x.d0 + ids.x.d1 * ids.BASE) & ((1 << 128) - 1)"#}),
269(UINT256_ADD, indoc! {r#"sum_low = ids.a.low + ids.b.low
270ids.carry_low = 1 if sum_low >= ids.SHIFT else 0
271sum_high = ids.a.high + ids.b.high + ids.carry_low
272ids.carry_high = 1 if sum_high >= ids.SHIFT else 0"#}),
273(UINT256_ADD_LOW, indoc! {r#"sum_low = ids.a.low + ids.b.low
274ids.carry_low = 1 if sum_low >= ids.SHIFT else 0"#}),
275(UINT128_ADD, indoc! {r#"res = ids.a + ids.b
276ids.carry = 1 if res >= ids.SHIFT else 0"#}),
277(UINT256_SUB, indoc! {r#"def split(num: int, num_bits_shift: int = 128, length: int = 2):
278    a = []
279    for _ in range(length):
280        a.append( num & ((1 << num_bits_shift) - 1) )
281        num = num >> num_bits_shift
282    return tuple(a)
283
284def pack(z, num_bits_shift: int = 128) -> int:
285    limbs = (z.low, z.high)
286    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
287
288a = pack(ids.a)
289b = pack(ids.b)
290res = (a - b)%2**256
291res_split = split(res)
292ids.res.low = res_split[0]
293ids.res.high = res_split[1]"#}),
294(UINT256_SQRT, indoc! {r#"from starkware.python.math_utils import isqrt
295n = (ids.n.high << 128) + ids.n.low
296root = isqrt(n)
297assert 0 <= root < 2 ** 128
298ids.root.low = root
299ids.root.high = 0"#}),
300(UINT256_SQRT_FELT, indoc! {r#"from starkware.python.math_utils import isqrt
301n = (ids.n.high << 128) + ids.n.low
302root = isqrt(n)
303assert 0 <= root < 2 ** 128
304ids.root = root"#}),
305(UINT256_SIGNED_NN, indoc! {r#"memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0"#}),
306(UINT256_UNSIGNED_DIV_REM, indoc! {r#"a = (ids.a.high << 128) + ids.a.low
307div = (ids.div.high << 128) + ids.div.low
308quotient, remainder = divmod(a, div)
309
310ids.quotient.low = quotient & ((1 << 128) - 1)
311ids.quotient.high = quotient >> 128
312ids.remainder.low = remainder & ((1 << 128) - 1)
313ids.remainder.high = remainder >> 128"#}),
314(UINT256_EXPANDED_UNSIGNED_DIV_REM, indoc! {r#"a = (ids.a.high << 128) + ids.a.low
315div = (ids.div.b23 << 128) + ids.div.b01
316quotient, remainder = divmod(a, div)
317
318ids.quotient.low = quotient & ((1 << 128) - 1)
319ids.quotient.high = quotient >> 128
320ids.remainder.low = remainder & ((1 << 128) - 1)
321ids.remainder.high = remainder >> 128"#}),
322(UINT256_MUL_DIV_MOD, indoc! {r#"a = (ids.a.high << 128) + ids.a.low
323b = (ids.b.high << 128) + ids.b.low
324div = (ids.div.high << 128) + ids.div.low
325quotient, remainder = divmod(a * b, div)
326
327ids.quotient_low.low = quotient & ((1 << 128) - 1)
328ids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1)
329ids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1)
330ids.quotient_high.high = quotient >> 384
331ids.remainder.low = remainder & ((1 << 128) - 1)
332ids.remainder.high = remainder >> 128"#}),
333(USORT_ENTER_SCOPE, indoc! {r#"vm_enter_scope(dict(__usort_max_size = globals().get('__usort_max_size')))"#}),
334(USORT_BODY, indoc! {r#"from collections import defaultdict
335
336input_ptr = ids.input
337input_len = int(ids.input_len)
338if __usort_max_size is not None:
339    assert input_len <= __usort_max_size, (
340        f"usort() can only be used with input_len<={__usort_max_size}. "
341        f"Got: input_len={input_len}."
342    )
343
344positions_dict = defaultdict(list)
345for i in range(input_len):
346    val = memory[input_ptr + i]
347    positions_dict[val].append(i)
348
349output = sorted(positions_dict.keys())
350ids.output_len = len(output)
351ids.output = segments.gen_arg(output)
352ids.multiplicities = segments.gen_arg([len(positions_dict[k]) for k in output])"#}),
353(USORT_VERIFY, indoc! {r#"last_pos = 0
354positions = positions_dict[ids.value][::-1]"#}),
355(USORT_VERIFY_MULTIPLICITY_ASSERT, indoc! {r#"assert len(positions) == 0"#}),
356(USORT_VERIFY_MULTIPLICITY_BODY, indoc! {r#"current_pos = positions.pop()
357ids.next_item_index = current_pos - last_pos
358last_pos = current_pos + 1"#}),
359(BLAKE2S_COMPUTE, indoc! {r#"from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func
360compute_blake2s_func(segments=segments, output_ptr=ids.output)"#}),
361(BLAKE2S_FINALIZE, indoc! {r#"# Add dummy pairs of input and output.
362from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
363
364_n_packed_instances = int(ids.N_PACKED_INSTANCES)
365assert 0 <= _n_packed_instances < 20
366_blake2s_input_chunk_size_felts = int(ids.INPUT_BLOCK_FELTS)
367assert 0 <= _blake2s_input_chunk_size_felts < 100
368
369message = [0] * _blake2s_input_chunk_size_felts
370modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
371output = blake2s_compress(
372    message=message,
373    h=modified_iv,
374    t0=0,
375    t1=0,
376    f0=0xffffffff,
377    f1=0,
378)
379padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
380segments.write_arg(ids.blake2s_ptr_end, padding)"#}),
381(BLAKE2S_FINALIZE_V2, indoc! {r#"# Add dummy pairs of input and output.
382from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
383
384_n_packed_instances = int(ids.N_PACKED_INSTANCES)
385assert 0 <= _n_packed_instances < 20
386_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
387assert 0 <= _blake2s_input_chunk_size_felts < 100
388
389message = [0] * _blake2s_input_chunk_size_felts
390modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
391output = blake2s_compress(
392    message=message,
393    h=modified_iv,
394    t0=0,
395    t1=0,
396    f0=0xffffffff,
397    f1=0,
398)
399padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
400segments.write_arg(ids.blake2s_ptr_end, padding)"#}),
401(BLAKE2S_FINALIZE_V3, indoc! {r#"# Add dummy pairs of input and output.
402from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
403
404_n_packed_instances = int(ids.N_PACKED_INSTANCES)
405assert 0 <= _n_packed_instances < 20
406_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
407assert 0 <= _blake2s_input_chunk_size_felts < 100
408
409message = [0] * _blake2s_input_chunk_size_felts
410modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
411output = blake2s_compress(
412    message=message,
413    h=modified_iv,
414    t0=0,
415    t1=0,
416    f0=0xffffffff,
417    f1=0,
418)
419padding = (message + modified_iv + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
420segments.write_arg(ids.blake2s_ptr_end, padding)"#}),
421(BLAKE2S_ADD_UINT256, indoc! {r#"B = 32
422MASK = 2 ** 32 - 1
423segments.write_arg(ids.data, [(ids.low >> (B * i)) & MASK for i in range(4)])
424segments.write_arg(ids.data + 4, [(ids.high >> (B * i)) & MASK for i in range(4)])"#}),
425(BLAKE2S_ADD_UINT256_BIGEND, indoc! {r#"B = 32
426MASK = 2 ** 32 - 1
427segments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])
428segments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])"#}),
429(IS_LESS_THAN_63_BITS_AND_NOT_END, indoc! {r#"memory[ap] = to_felt_or_relocatable((ids.end != ids.packed_values) and (memory[ids.packed_values] < 2**63))"#}),
430(BLAKE2S_UNPACK_FELTS, indoc! {r#"offset = 0
431for i in range(ids.packed_values_len):
432    val = (memory[ids.packed_values + i] % PRIME)
433    val_len = 2 if val < 2**63 else 8
434    if val_len == 8:
435        val += 2**255
436    for i in range(val_len - 1, -1, -1):
437        val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
438    assert val == 0
439    offset += val_len"#}),
440(EXAMPLE_BLAKE2S_COMPRESS, indoc! {r#"from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
441
442_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
443assert 0 <= _blake2s_input_chunk_size_felts < 100
444
445new_state = blake2s_compress(
446    message=memory.get_range(ids.blake2s_start, _blake2s_input_chunk_size_felts),
447    h=[IV[0] ^ 0x01010020] + IV[1:],
448    t0=ids.n_bytes,
449    t1=0,
450    f0=0xffffffff,
451    f1=0,
452)
453
454segments.write_arg(ids.output, new_state)"#}),
455(NONDET_BIGINT3_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import split
456
457segments.write_arg(ids.res.address_, split(value))"#}),
458(NONDET_BIGINT3_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import split
459segments.write_arg(ids.res.address_, split(value))"#}),
460(VERIFY_ZERO_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
461
462q, r = divmod(pack(ids.val, PRIME), SECP_P)
463assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
464ids.q = q % PRIME"#}),
465(VERIFY_ZERO_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P
466q, r = divmod(pack(ids.val, PRIME), SECP_P)
467assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
468ids.q = q % PRIME"#}),
469(VERIFY_ZERO_V3, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
470SECP_P = 2**255-19
471to_assert = pack(ids.val, PRIME)
472q, r = divmod(pack(ids.val, PRIME), SECP_P)
473assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
474ids.q = q % PRIME"#}),
475(VERIFY_ZERO_EXTERNAL_SECP, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
476
477q, r = divmod(pack(ids.val, PRIME), SECP_P)
478assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
479ids.q = q % PRIME"#}),
480(REDUCE_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
481
482value = pack(ids.x, PRIME) % SECP_P"#}),
483(REDUCE_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
484value = pack(ids.x, PRIME) % SECP_P"#}),
485(REDUCE_ED25519, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
486SECP_P=2**255-19
487
488value = pack(ids.x, PRIME) % SECP_P"#}),
489(UNSAFE_KECCAK, indoc! {r#"from eth_hash.auto import keccak
490
491data, length = ids.data, ids.length
492
493if '__keccak_max_size' in globals():
494    assert length <= __keccak_max_size, \
495        f'unsafe_keccak() can only be used with length<={__keccak_max_size}. ' \
496        f'Got: length={length}.'
497
498keccak_input = bytearray()
499for word_i, byte_i in enumerate(range(0, length, 16)):
500    word = memory[data + word_i]
501    n_bytes = min(16, length - byte_i)
502    assert 0 <= word < 2 ** (8 * n_bytes)
503    keccak_input += word.to_bytes(n_bytes, 'big')
504
505hashed = keccak(keccak_input)
506ids.high = int.from_bytes(hashed[:16], 'big')
507ids.low = int.from_bytes(hashed[16:32], 'big')"#}),
508(UNSAFE_KECCAK_FINALIZE, indoc! {r#"from eth_hash.auto import keccak
509keccak_input = bytearray()
510n_elms = ids.keccak_state.end_ptr - ids.keccak_state.start_ptr
511for word in memory.get_range(ids.keccak_state.start_ptr, n_elms):
512    keccak_input += word.to_bytes(16, 'big')
513hashed = keccak(keccak_input)
514ids.high = int.from_bytes(hashed[:16], 'big')
515ids.low = int.from_bytes(hashed[16:32], 'big')"#}),
516(IS_ZERO_NONDET, indoc! {r#"memory[ap] = to_felt_or_relocatable(x == 0)"#}),
517(IS_ZERO_INT, indoc! {r#"memory[ap] = int(x == 0)"#}),
518(IS_ZERO_PACK_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
519
520x = pack(ids.x, PRIME) % SECP_P"#}),
521(IS_ZERO_PACK_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
522x = pack(ids.x, PRIME) % SECP_P"#}),
523(IS_ZERO_PACK_EXTERNAL_SECP_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
524
525x = pack(ids.x, PRIME) % SECP_P"#}),
526(IS_ZERO_PACK_EXTERNAL_SECP_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
527x = pack(ids.x, PRIME) % SECP_P"#}),
528(IS_ZERO_PACK_ED25519, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
529SECP_P=2**255-19
530
531x = pack(ids.x, PRIME) % SECP_P"#}),
532(IS_ZERO_ASSIGN_SCOPE_VARS, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P
533from starkware.python.math_utils import div_mod
534
535value = x_inv = div_mod(1, x, SECP_P)"#}),
536(IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP, indoc! {r#"from starkware.python.math_utils import div_mod
537
538value = x_inv = div_mod(1, x, SECP_P)"#}),
539(IS_ZERO_ASSIGN_SCOPE_VARS_ED25519, indoc! {r#"SECP_P=2**255-19
540from starkware.python.math_utils import div_mod
541
542value = x_inv = div_mod(1, x, SECP_P)"#}),
543(DIV_MOD_N_PACKED_DIVMOD_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import N, pack
544from starkware.python.math_utils import div_mod, safe_div
545
546a = pack(ids.a, PRIME)
547b = pack(ids.b, PRIME)
548value = res = div_mod(a, b, N)"#}),
549(DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
550from starkware.python.math_utils import div_mod, safe_div
551
552a = pack(ids.a, PRIME)
553b = pack(ids.b, PRIME)
554value = res = div_mod(a, b, N)"#}),
555(DIV_MOD_N_SAFE_DIV, indoc! {r#"value = k = safe_div(res * b - a, N)"#}),
556(GET_FELT_BIT_LENGTH, indoc! {r#"x = ids.x
557ids.bit_length = x.bit_length()"#}),
558(BIGINT_PACK_DIV_MOD, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
559from starkware.cairo.common.math_utils import as_int
560from starkware.python.math_utils import div_mod, safe_div
561
562p = pack(ids.P, PRIME)
563x = pack(ids.x, PRIME) + as_int(ids.x.d3, PRIME) * ids.BASE ** 3 + as_int(ids.x.d4, PRIME) * ids.BASE ** 4
564y = pack(ids.y, PRIME)
565
566value = res = div_mod(x, y, p)"#}),
567(BIGINT_SAFE_DIV, indoc! {r#"k = safe_div(res * y - x, p)
568value = k if k > 0 else 0 - k
569ids.flag = 1 if k > 0 else 0"#}),
570(DIV_MOD_N_SAFE_DIV_PLUS_ONE, indoc! {r#"value = k_plus_one = safe_div(res * b - a, N) + 1"#}),
571(GET_POINT_FROM_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
572
573x_cube_int = pack(ids.x_cube, PRIME) % SECP_P
574y_square_int = (x_cube_int + ids.BETA) % SECP_P
575y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P)
576
577# We need to decide whether to take y or SECP_P - y.
578if ids.v % 2 == y % 2:
579    value = y
580else:
581    value = (-y) % SECP_P"#}),
582(EC_NEGATE, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
583
584y = pack(ids.point.y, PRIME) % SECP_P
585# The modulo operation in python always returns a nonnegative number.
586value = (-y) % SECP_P"#}),
587(EC_NEGATE_EMBEDDED_SECP, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
588SECP_P = 2**255-19
589
590y = pack(ids.point.y, PRIME) % SECP_P
591# The modulo operation in python always returns a nonnegative number.
592value = (-y) % SECP_P"#}),
593(EC_DOUBLE_SLOPE_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
594from starkware.python.math_utils import ec_double_slope
595
596# Compute the slope.
597x = pack(ids.point.x, PRIME)
598y = pack(ids.point.y, PRIME)
599value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)"#}),
600(EC_DOUBLE_SLOPE_V2, indoc! {r#"from starkware.python.math_utils import ec_double_slope
601from starkware.cairo.common.cairo_secp.secp_utils import pack
602SECP_P = 2**255-19
603
604# Compute the slope.
605x = pack(ids.point.x, PRIME)
606y = pack(ids.point.y, PRIME)
607value = slope = ec_double_slope(point=(x, y), alpha=42204101795669822316448953119945047945709099015225996174933988943478124189485, p=SECP_P)"#}),
608(EC_DOUBLE_SLOPE_V3, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
609from starkware.python.math_utils import div_mod
610
611# Compute the slope.
612x = pack(ids.pt.x, PRIME)
613y = pack(ids.pt.y, PRIME)
614value = slope = div_mod(3 * x ** 2, 2 * y, SECP_P)"#}),
615(EC_DOUBLE_SLOPE_V4, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA, SECP256R1_P
616from starkware.cairo.common.cairo_secp.secp_utils import pack
617from starkware.python.math_utils import ec_double_slope
618
619# Compute the slope.
620x = pack(ids.point.x, SECP256R1_P)
621y = pack(ids.point.y, SECP256R1_P)
622value = slope = ec_double_slope(point=(x, y), alpha=SECP256R1_ALPHA, p=SECP256R1_P)"#}),
623(EC_DOUBLE_SLOPE_V5, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA, SECP256R1_P
624from starkware.cairo.common.cairo_secp.secp_utils import pack
625from starkware.python.math_utils import ec_double_slope
626
627# Compute the slope.
628x = pack(ids.point.x, PRIME)
629y = pack(ids.point.y, PRIME)
630value = slope = ec_double_slope(point=(x, y), alpha=SECP256R1_ALPHA, p=SECP256R1_P)"#}),
631(EC_DOUBLE_SLOPE_EXTERNAL_CONSTS, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
632from starkware.python.math_utils import ec_double_slope
633
634# Compute the slope.
635x = pack(ids.point.x, PRIME)
636y = pack(ids.point.y, PRIME)
637value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)"#}),
638(COMPUTE_SLOPE_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
639from starkware.python.math_utils import line_slope
640
641# Compute the slope.
642x0 = pack(ids.point0.x, PRIME)
643y0 = pack(ids.point0.y, PRIME)
644x1 = pack(ids.point1.x, PRIME)
645y1 = pack(ids.point1.y, PRIME)
646value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#}),
647(COMPUTE_SLOPE_V2, indoc! {r#"from starkware.python.math_utils import line_slope
648from starkware.cairo.common.cairo_secp.secp_utils import pack
649SECP_P = 2**255-19
650# Compute the slope.
651x0 = pack(ids.point0.x, PRIME)
652y0 = pack(ids.point0.y, PRIME)
653x1 = pack(ids.point1.x, PRIME)
654y1 = pack(ids.point1.y, PRIME)
655value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#}),
656(COMPUTE_SLOPE_SECP256R1_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
657from starkware.python.math_utils import line_slope
658
659# Compute the slope.
660x0 = pack(ids.point0.x, PRIME)
661y0 = pack(ids.point0.y, PRIME)
662x1 = pack(ids.point1.x, PRIME)
663y1 = pack(ids.point1.y, PRIME)
664value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#}),
665(COMPUTE_SLOPE_SECP256R1_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
666from starkware.cairo.common.cairo_secp.secp_utils import pack
667from starkware.python.math_utils import line_slope
668
669# Compute the slope.
670x0 = pack(ids.point0.x, PRIME)
671y0 = pack(ids.point0.y, PRIME)
672x1 = pack(ids.point1.x, PRIME)
673y1 = pack(ids.point1.y, PRIME)
674value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP256R1_P)"#}),
675(IMPORT_SECP256R1_P, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P"#}),
676(COMPUTE_SLOPE_WHITELIST, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
677from starkware.python.math_utils import div_mod
678
679# Compute the slope.
680x0 = pack(ids.pt0.x, PRIME)
681y0 = pack(ids.pt0.y, PRIME)
682x1 = pack(ids.pt1.x, PRIME)
683y1 = pack(ids.pt1.y, PRIME)
684value = slope = div_mod(y0 - y1, x0 - x1, SECP_P)"#}),
685(EC_DOUBLE_ASSIGN_NEW_X_V1, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
686
687slope = pack(ids.slope, PRIME)
688x = pack(ids.point.x, PRIME)
689y = pack(ids.point.y, PRIME)
690
691value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P"#}),
692(EC_DOUBLE_ASSIGN_NEW_X_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
693
694slope = pack(ids.slope, PRIME)
695x = pack(ids.point.x, PRIME)
696y = pack(ids.point.y, PRIME)
697
698value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P"#}),
699(EC_DOUBLE_ASSIGN_NEW_X_V3, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
700SECP_P = 2**255-19
701
702slope = pack(ids.slope, PRIME)
703x = pack(ids.point.x, PRIME)
704y = pack(ids.point.y, PRIME)
705
706value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P"#}),
707(EC_DOUBLE_ASSIGN_NEW_X_V4, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
708
709slope = pack(ids.slope, PRIME)
710x = pack(ids.pt.x, PRIME)
711y = pack(ids.pt.y, PRIME)
712
713value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P"#}),
714(EC_DOUBLE_ASSIGN_NEW_Y, indoc! {r#"value = new_y = (slope * (x - new_x) - y) % SECP_P"#}),
715(SHA256_INPUT, indoc! {r#"ids.full_word = int(ids.n_bytes >= 4)"#}),
716(SHA256_MAIN_CONSTANT_INPUT_LENGTH, indoc! {r#"from starkware.cairo.common.cairo_sha256.sha256_utils import (
717    IV, compute_message_schedule, sha2_compress_function)
718
719_sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS)
720assert 0 <= _sha256_input_chunk_size_felts < 100
721
722w = compute_message_schedule(memory.get_range(
723    ids.sha256_start, _sha256_input_chunk_size_felts))
724new_state = sha2_compress_function(IV, w)
725segments.write_arg(ids.output, new_state)"#}),
726(SHA256_MAIN_ARBITRARY_INPUT_LENGTH, indoc! {r#"from starkware.cairo.common.cairo_sha256.sha256_utils import (
727    compute_message_schedule, sha2_compress_function)
728
729_sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS)
730assert 0 <= _sha256_input_chunk_size_felts < 100
731_sha256_state_size_felts = int(ids.SHA256_STATE_SIZE_FELTS)
732assert 0 <= _sha256_state_size_felts < 100
733w = compute_message_schedule(memory.get_range(
734    ids.sha256_start, _sha256_input_chunk_size_felts))
735new_state = sha2_compress_function(memory.get_range(ids.state, _sha256_state_size_felts), w)
736segments.write_arg(ids.output, new_state)"#}),
737(SHA256_FINALIZE, indoc! {r#"# Add dummy pairs of input and output.
738from starkware.cairo.common.cairo_sha256.sha256_utils import (
739    IV, compute_message_schedule, sha2_compress_function)
740
741_block_size = int(ids.BLOCK_SIZE)
742assert 0 <= _block_size < 20
743_sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS)
744assert 0 <= _sha256_input_chunk_size_felts < 100
745
746message = [0] * _sha256_input_chunk_size_felts
747w = compute_message_schedule(message)
748output = sha2_compress_function(IV, w)
749padding = (message + IV + output) * (_block_size - 1)
750segments.write_arg(ids.sha256_ptr_end, padding)"#}),
751(KECCAK_WRITE_ARGS, indoc! {r#"segments.write_arg(ids.inputs, [ids.low % 2 ** 64, ids.low // 2 ** 64])
752segments.write_arg(ids.inputs + 2, [ids.high % 2 ** 64, ids.high // 2 ** 64])"#}),
753(COMPARE_BYTES_IN_WORD_NONDET, indoc! {r#"memory[ap] = to_felt_or_relocatable(ids.n_bytes < ids.BYTES_IN_WORD)"#}),
754(COMPARE_KECCAK_FULL_RATE_IN_BYTES_NONDET, indoc! {r#"memory[ap] = to_felt_or_relocatable(ids.n_bytes >= ids.KECCAK_FULL_RATE_IN_BYTES)"#}),
755(BLOCK_PERMUTATION, indoc! {r#"from starkware.cairo.common.keccak_utils.keccak_utils import keccak_func
756_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
757assert 0 <= _keccak_state_size_felts < 100
758
759output_values = keccak_func(memory.get_range(
760    ids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts))
761segments.write_arg(ids.keccak_ptr, output_values)"#}),
762// The 0.10.3 whitelist uses this variant (instead of the one used by the common library), but both hints have the same behaviour
763// We should check for future refactors that may discard one of the variants
764(BLOCK_PERMUTATION_WHITELIST_V1, indoc! {r#"from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
765_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
766assert 0 <= _keccak_state_size_felts < 100
767
768output_values = keccak_func(memory.get_range(
769    ids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts))
770segments.write_arg(ids.keccak_ptr, output_values)"#}),
771(BLOCK_PERMUTATION_WHITELIST_V2, indoc! {r#"from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
772_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
773assert 0 <= _keccak_state_size_felts < 100
774output_values = keccak_func(memory.get_range(
775    ids.keccak_ptr_start, _keccak_state_size_felts))
776segments.write_arg(ids.output, output_values)"#}),
777(CAIRO_KECCAK_INPUT_IS_FULL_WORD, indoc! {r#"ids.full_word = int(ids.n_bytes >= 8)"#}),
778(CAIRO_KECCAK_FINALIZE_V1, indoc! {r#"# Add dummy pairs of input and output.
779_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
780_block_size = int(ids.BLOCK_SIZE)
781assert 0 <= _keccak_state_size_felts < 100
782assert 0 <= _block_size < 10
783inp = [0] * _keccak_state_size_felts
784padding = (inp + keccak_func(inp)) * _block_size
785segments.write_arg(ids.keccak_ptr_end, padding)"#}),
786(CAIRO_KECCAK_FINALIZE_V2, indoc! {r#"# Add dummy pairs of input and output.
787_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
788_block_size = int(ids.BLOCK_SIZE)
789assert 0 <= _keccak_state_size_felts < 100
790assert 0 <= _block_size < 1000
791inp = [0] * _keccak_state_size_felts
792padding = (inp + keccak_func(inp)) * _block_size
793segments.write_arg(ids.keccak_ptr_end, padding)"#}),
794(FAST_EC_ADD_ASSIGN_NEW_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
795
796slope = pack(ids.slope, PRIME)
797x0 = pack(ids.point0.x, PRIME)
798x1 = pack(ids.point1.x, PRIME)
799y0 = pack(ids.point0.y, PRIME)
800
801value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P"#}),
802(FAST_EC_ADD_ASSIGN_NEW_X_V2, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
803SECP_P = 2**255-19
804
805slope = pack(ids.slope, PRIME)
806x0 = pack(ids.point0.x, PRIME)
807x1 = pack(ids.point1.x, PRIME)
808y0 = pack(ids.point0.y, PRIME)
809
810value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P"#}),
811(FAST_EC_ADD_ASSIGN_NEW_X_V3, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
812
813slope = pack(ids.slope, PRIME)
814x0 = pack(ids.pt0.x, PRIME)
815x1 = pack(ids.pt1.x, PRIME)
816y0 = pack(ids.pt0.y, PRIME)
817
818value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P"#}),
819(FAST_EC_ADD_ASSIGN_NEW_Y, indoc! {r#"value = new_y = (slope * (x0 - new_x) - y0) % SECP_P"#}),
820(EC_MUL_INNER, indoc! {r#"memory[ap] = (ids.scalar % PRIME) % 2"#}),
821(RELOCATE_SEGMENT, indoc! {r#"memory.add_relocation_rule(src_ptr=ids.src_ptr, dest_ptr=ids.dest_ptr)"#}),
822(TEMPORARY_ARRAY, indoc! {r#"ids.temporary_array = segments.add_temp_segment()"#}),
823(VERIFY_ECDSA_SIGNATURE, indoc! {r#"ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))"#}),
824(SPLIT_OUTPUT_0, indoc! {r#"ids.output0_low = ids.output0 & ((1 << 128) - 1)
825ids.output0_high = ids.output0 >> 128"#}),
826(SPLIT_OUTPUT_1, indoc! {r#"ids.output1_low = ids.output1 & ((1 << 128) - 1)
827ids.output1_high = ids.output1 >> 128"#}),
828(SPLIT_INPUT_3, indoc! {r#"ids.high3, ids.low3 = divmod(memory[ids.inputs + 3], 256)"#}),
829(SPLIT_INPUT_6, indoc! {r#"ids.high6, ids.low6 = divmod(memory[ids.inputs + 6], 256 ** 2)"#}),
830(SPLIT_INPUT_9, indoc! {r#"ids.high9, ids.low9 = divmod(memory[ids.inputs + 9], 256 ** 3)"#}),
831(SPLIT_INPUT_12, indoc! {r#"ids.high12, ids.low12 = divmod(memory[ids.inputs + 12], 256 ** 4)"#}),
832(SPLIT_INPUT_15, indoc! {r#"ids.high15, ids.low15 = divmod(memory[ids.inputs + 15], 256 ** 5)"#}),
833(SPLIT_N_BYTES, indoc! {r#"ids.n_words_to_copy, ids.n_bytes_left = divmod(ids.n_bytes, ids.BYTES_IN_WORD)"#}),
834(SPLIT_OUTPUT_MID_LOW_HIGH, indoc! {r#"tmp, ids.output1_low = divmod(ids.output1, 256 ** 7)
835ids.output1_high, ids.output1_mid = divmod(tmp, 2 ** 128)"#}),
836(NONDET_N_GREATER_THAN_10, indoc! {r#"memory[ap] = to_felt_or_relocatable(ids.n >= 10)"#}),
837(NONDET_N_GREATER_THAN_2, indoc! {r#"memory[ap] = to_felt_or_relocatable(ids.n >= 2)"#}),
838(RANDOM_EC_POINT, indoc! {r#"from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME
839from starkware.python.math_utils import random_ec_point
840from starkware.python.utils import to_bytes
841
842# Define a seed for random_ec_point that's dependent on all the input, so that:
843#   (1) The added point s is deterministic.
844#   (2) It's hard to choose inputs for which the builtin will fail.
845seed = b"".join(map(to_bytes, [ids.p.x, ids.p.y, ids.m, ids.q.x, ids.q.y]))
846ids.s.x, ids.s.y = random_ec_point(FIELD_PRIME, ALPHA, BETA, seed)"#}),
847(CHAINED_EC_OP_RANDOM_EC_POINT, indoc! {r#"from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME
848from starkware.python.math_utils import random_ec_point
849from starkware.python.utils import to_bytes
850
851n_elms = ids.len
852assert isinstance(n_elms, int) and n_elms >= 0, \
853    f'Invalid value for len. Got: {n_elms}.'
854if '__chained_ec_op_max_len' in globals():
855    assert n_elms <= __chained_ec_op_max_len, \
856        f'chained_ec_op() can only be used with len<={__chained_ec_op_max_len}. ' \
857        f'Got: n_elms={n_elms}.'
858
859# Define a seed for random_ec_point that's dependent on all the input, so that:
860#   (1) The added point s is deterministic.
861#   (2) It's hard to choose inputs for which the builtin will fail.
862seed = b"".join(
863    map(
864        to_bytes,
865        [
866            ids.p.x,
867            ids.p.y,
868            *memory.get_range(ids.m, n_elms),
869            *memory.get_range(ids.q.address_, 2 * n_elms),
870        ],
871    )
872)
873ids.s.x, ids.s.y = random_ec_point(FIELD_PRIME, ALPHA, BETA, seed)"#}),
874(RECOVER_Y, indoc! {r#"from starkware.crypto.signature.signature import ALPHA, BETA, FIELD_PRIME
875from starkware.python.math_utils import recover_y
876ids.p.x = ids.x
877# This raises an exception if `x` is not on the curve.
878ids.p.y = recover_y(ids.x, ALPHA, BETA, FIELD_PRIME)"#}),
879(PACK_MODN_DIV_MODN, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
880from starkware.python.math_utils import div_mod, safe_div
881
882N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
883x = pack(ids.x, PRIME) % N
884s = pack(ids.s, PRIME) % N
885value = res = div_mod(x, s, N)"#}),
886(XS_SAFE_DIV, indoc! {r#"value = k = safe_div(res * s - x, N)"#}),
887// The following hints support the lib https://github.com/NethermindEth/research-basic-Cairo-operations-big-integers/blob/main/lib
888(UINT384_UNSIGNED_DIV_REM, indoc! {r#"def split(num: int, num_bits_shift: int, length: int):
889    a = []
890    for _ in range(length):
891        a.append( num & ((1 << num_bits_shift) - 1) )
892        num = num >> num_bits_shift
893    return tuple(a)
894
895def pack(z, num_bits_shift: int) -> int:
896    limbs = (z.d0, z.d1, z.d2)
897    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
898
899a = pack(ids.a, num_bits_shift = 128)
900div = pack(ids.div, num_bits_shift = 128)
901quotient, remainder = divmod(a, div)
902
903quotient_split = split(quotient, num_bits_shift=128, length=3)
904assert len(quotient_split) == 3
905
906ids.quotient.d0 = quotient_split[0]
907ids.quotient.d1 = quotient_split[1]
908ids.quotient.d2 = quotient_split[2]
909
910remainder_split = split(remainder, num_bits_shift=128, length=3)
911ids.remainder.d0 = remainder_split[0]
912ids.remainder.d1 = remainder_split[1]
913ids.remainder.d2 = remainder_split[2]"#}),
914(UINT384_SPLIT_128, indoc! {r#"ids.low = ids.a & ((1<<128) - 1)
915ids.high = ids.a >> 128"#}),
916(ADD_NO_UINT384_CHECK, indoc! {r#"sum_d0 = ids.a.d0 + ids.b.d0
917ids.carry_d0 = 1 if sum_d0 >= ids.SHIFT else 0
918sum_d1 = ids.a.d1 + ids.b.d1 + ids.carry_d0
919ids.carry_d1 = 1 if sum_d1 >= ids.SHIFT else 0
920sum_d2 = ids.a.d2 + ids.b.d2 + ids.carry_d1
921ids.carry_d2 = 1 if sum_d2 >= ids.SHIFT else 0"#}),
922(UINT384_SQRT, indoc! {r#"from starkware.python.math_utils import isqrt
923
924def split(num: int, num_bits_shift: int, length: int):
925    a = []
926    for _ in range(length):
927        a.append( num & ((1 << num_bits_shift) - 1) )
928        num = num >> num_bits_shift
929    return tuple(a)
930
931def pack(z, num_bits_shift: int) -> int:
932    limbs = (z.d0, z.d1, z.d2)
933    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
934
935a = pack(ids.a, num_bits_shift=128)
936root = isqrt(a)
937assert 0 <= root < 2 ** 192
938root_split = split(root, num_bits_shift=128, length=3)
939ids.root.d0 = root_split[0]
940ids.root.d1 = root_split[1]
941ids.root.d2 = root_split[2]"#}),
942(SUB_REDUCED_A_AND_REDUCED_B, indoc! {r#"def split(num: int, num_bits_shift: int, length: int):
943    a = []
944    for _ in range(length):
945        a.append( num & ((1 << num_bits_shift) - 1) )
946        num = num >> num_bits_shift
947    return tuple(a)
948
949def pack(z, num_bits_shift: int) -> int:
950    limbs = (z.d0, z.d1, z.d2)
951    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
952
953a = pack(ids.a, num_bits_shift = 128)
954b = pack(ids.b, num_bits_shift = 128)
955p = pack(ids.p, num_bits_shift = 128)
956
957res = (a - b) % p
958
959
960res_split = split(res, num_bits_shift=128, length=3)
961
962ids.res.d0 = res_split[0]
963ids.res.d1 = res_split[1]
964ids.res.d2 = res_split[2]"#}),
965(UNSIGNED_DIV_REM_UINT768_BY_UINT384, indoc! {r#"def split(num: int, num_bits_shift: int, length: int):
966    a = []
967    for _ in range(length):
968        a.append( num & ((1 << num_bits_shift) - 1) )
969        num = num >> num_bits_shift 
970    return tuple(a)
971
972def pack(z, num_bits_shift: int) -> int:
973    limbs = (z.d0, z.d1, z.d2)
974    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
975    
976def pack_extended(z, num_bits_shift: int) -> int:
977    limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)
978    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
979
980a = pack_extended(ids.a, num_bits_shift = 128)
981div = pack(ids.div, num_bits_shift = 128)
982
983quotient, remainder = divmod(a, div)
984
985quotient_split = split(quotient, num_bits_shift=128, length=6)
986
987ids.quotient.d0 = quotient_split[0]
988ids.quotient.d1 = quotient_split[1]
989ids.quotient.d2 = quotient_split[2]
990ids.quotient.d3 = quotient_split[3]
991ids.quotient.d4 = quotient_split[4]
992ids.quotient.d5 = quotient_split[5]
993
994remainder_split = split(remainder, num_bits_shift=128, length=3)
995ids.remainder.d0 = remainder_split[0]
996ids.remainder.d1 = remainder_split[1]
997ids.remainder.d2 = remainder_split[2]"#}),
998// equal to UNSIGNED_DIV_REM_UINT768_BY_UINT384 but with some whitespace removed
999// in the `num = num >> num_bits_shift` and between `pack` and `pack_extended`
1000(UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED, indoc! {r#"def split(num: int, num_bits_shift: int, length: int):
1001    a = []
1002    for _ in range(length):
1003        a.append( num & ((1 << num_bits_shift) - 1) )
1004        num = num >> num_bits_shift
1005    return tuple(a)
1006
1007def pack(z, num_bits_shift: int) -> int:
1008    limbs = (z.d0, z.d1, z.d2)
1009    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1010
1011def pack_extended(z, num_bits_shift: int) -> int:
1012    limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)
1013    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1014
1015a = pack_extended(ids.a, num_bits_shift = 128)
1016div = pack(ids.div, num_bits_shift = 128)
1017
1018quotient, remainder = divmod(a, div)
1019
1020quotient_split = split(quotient, num_bits_shift=128, length=6)
1021
1022ids.quotient.d0 = quotient_split[0]
1023ids.quotient.d1 = quotient_split[1]
1024ids.quotient.d2 = quotient_split[2]
1025ids.quotient.d3 = quotient_split[3]
1026ids.quotient.d4 = quotient_split[4]
1027ids.quotient.d5 = quotient_split[5]
1028
1029remainder_split = split(remainder, num_bits_shift=128, length=3)
1030ids.remainder.d0 = remainder_split[0]
1031ids.remainder.d1 = remainder_split[1]
1032ids.remainder.d2 = remainder_split[2]"#}),
1033(UINT384_SIGNED_NN, indoc! {r#"memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0"#}),
1034(IMPORT_SECP256R1_ALPHA, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA"#}),
1035(IMPORT_SECP256R1_N, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N"#}),
1036(UINT384_GET_SQUARE_ROOT, indoc! {r#"from starkware.python.math_utils import is_quad_residue, sqrt
1037
1038def split(num: int, num_bits_shift: int = 128, length: int = 3):
1039    a = []
1040    for _ in range(length):
1041        a.append( num & ((1 << num_bits_shift) - 1) )
1042        num = num >> num_bits_shift
1043    return tuple(a)
1044
1045def pack(z, num_bits_shift: int = 128) -> int:
1046    limbs = (z.d0, z.d1, z.d2)
1047    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1048
1049
1050generator = pack(ids.generator)
1051x = pack(ids.x)
1052p = pack(ids.p)
1053
1054success_x = is_quad_residue(x, p)
1055root_x = sqrt(x, p) if success_x else None
1056
1057success_gx = is_quad_residue(generator*x, p)
1058root_gx = sqrt(generator*x, p) if success_gx else None
1059
1060# Check that one is 0 and the other is 1
1061if x != 0:
1062    assert success_x + success_gx ==1
1063
1064# `None` means that no root was found, but we need to transform these into a felt no matter what
1065if root_x == None:
1066    root_x = 0
1067if root_gx == None:
1068    root_gx = 0
1069ids.success_x = int(success_x)
1070ids.success_gx = int(success_gx)
1071split_root_x = split(root_x)
1072split_root_gx = split(root_gx)
1073ids.sqrt_x.d0 = split_root_x[0]
1074ids.sqrt_x.d1 = split_root_x[1]
1075ids.sqrt_x.d2 = split_root_x[2]
1076ids.sqrt_gx.d0 = split_root_gx[0]
1077ids.sqrt_gx.d1 = split_root_gx[1]
1078ids.sqrt_gx.d2 = split_root_gx[2]"#}),
1079(UINT256_GET_SQUARE_ROOT, indoc! {r#"from starkware.python.math_utils import is_quad_residue, sqrt
1080
1081def split(a: int):
1082    return (a & ((1 << 128) - 1), a >> 128)
1083
1084def pack(z) -> int:
1085    return z.low + (z.high << 128)
1086
1087generator = pack(ids.generator)
1088x = pack(ids.x)
1089p = pack(ids.p)
1090
1091success_x = is_quad_residue(x, p)
1092root_x = sqrt(x, p) if success_x else None
1093success_gx = is_quad_residue(generator*x, p)
1094root_gx = sqrt(generator*x, p) if success_gx else None
1095
1096# Check that one is 0 and the other is 1
1097if x != 0:
1098    assert success_x + success_gx == 1
1099
1100# `None` means that no root was found, but we need to transform these into a felt no matter what
1101if root_x == None:
1102    root_x = 0
1103if root_gx == None:
1104    root_gx = 0
1105ids.success_x = int(success_x)
1106ids.success_gx = int(success_gx)
1107split_root_x = split(root_x)
1108# print('split root x', split_root_x)
1109split_root_gx = split(root_gx)
1110ids.sqrt_x.low = split_root_x[0]
1111ids.sqrt_x.high = split_root_x[1]
1112ids.sqrt_gx.low = split_root_gx[0]
1113ids.sqrt_gx.high = split_root_gx[1]"#}),
1114(UINT384_DIV, indoc! {r#"from starkware.python.math_utils import div_mod
1115
1116def split(num: int, num_bits_shift: int, length: int):
1117    a = []
1118    for _ in range(length):
1119        a.append( num & ((1 << num_bits_shift) - 1) )
1120        num = num >> num_bits_shift
1121    return tuple(a)
1122
1123def pack(z, num_bits_shift: int) -> int:
1124    limbs = (z.d0, z.d1, z.d2)
1125    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1126
1127a = pack(ids.a, num_bits_shift = 128)
1128b = pack(ids.b, num_bits_shift = 128)
1129p = pack(ids.p, num_bits_shift = 128)
1130# For python3.8 and above the modular inverse can be computed as follows:
1131# b_inverse_mod_p = pow(b, -1, p)
1132# Instead we use the python3.7-friendly function div_mod from starkware.python.math_utils
1133b_inverse_mod_p = div_mod(1, b, p)
1134
1135
1136b_inverse_mod_p_split = split(b_inverse_mod_p, num_bits_shift=128, length=3)
1137
1138ids.b_inverse_mod_p.d0 = b_inverse_mod_p_split[0]
1139ids.b_inverse_mod_p.d1 = b_inverse_mod_p_split[1]
1140ids.b_inverse_mod_p.d2 = b_inverse_mod_p_split[2]"#}),
1141(INV_MOD_P_UINT256, indoc! {r#"from starkware.python.math_utils import div_mod
1142
1143def split(a: int):
1144    return (a & ((1 << 128) - 1), a >> 128)
1145
1146def pack(z, num_bits_shift: int) -> int:
1147    limbs = (z.low, z.high)
1148    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1149
1150a = pack(ids.a, 128)
1151b = pack(ids.b, 128)
1152p = pack(ids.p, 128)
1153# For python3.8 and above the modular inverse can be computed as follows:
1154# b_inverse_mod_p = pow(b, -1, p)
1155# Instead we use the python3.7-friendly function div_mod from starkware.python.math_utils
1156b_inverse_mod_p = div_mod(1, b, p)
1157
1158b_inverse_mod_p_split = split(b_inverse_mod_p)
1159
1160ids.b_inverse_mod_p.low = b_inverse_mod_p_split[0]
1161ids.b_inverse_mod_p.high = b_inverse_mod_p_split[1]"#}),
1162(HI_MAX_BITLEN, indoc! {r#"ids.len_hi = max(ids.scalar_u.d2.bit_length(), ids.scalar_v.d2.bit_length())-1"#}),
1163(QUAD_BIT, indoc! {r#"ids.quad_bit = (
1164    8 * ((ids.scalar_v >> ids.m) & 1)
1165    + 4 * ((ids.scalar_u >> ids.m) & 1)
1166    + 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)
1167    + ((ids.scalar_u >> (ids.m - 1)) & 1)
1168)"#}),
1169(INV_MOD_P_UINT512, indoc! {r#"def pack_512(u, num_bits_shift: int) -> int:
1170    limbs = (u.d0, u.d1, u.d2, u.d3)
1171    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1172
1173x = pack_512(ids.x, num_bits_shift = 128)
1174p = ids.p.low + (ids.p.high << 128)
1175x_inverse_mod_p = pow(x,-1, p)
1176
1177x_inverse_mod_p_split = (x_inverse_mod_p & ((1 << 128) - 1), x_inverse_mod_p >> 128)
1178
1179ids.x_inverse_mod_p.low = x_inverse_mod_p_split[0]
1180ids.x_inverse_mod_p.high = x_inverse_mod_p_split[1]"#}),
1181(DI_BIT, indoc! {r#"ids.dibit = ((ids.scalar_u >> ids.m) & 1) + 2 * ((ids.scalar_v >> ids.m) & 1)"#}),
1182(EC_RECOVER_DIV_MOD_N_PACKED, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
1183from starkware.python.math_utils import div_mod, safe_div
1184
1185N = pack(ids.n, PRIME)
1186x = pack(ids.x, PRIME) % N
1187s = pack(ids.s, PRIME) % N
1188value = res = div_mod(x, s, N)"#}),
1189(UINT512_UNSIGNED_DIV_REM, indoc! {r#"def split(num: int, num_bits_shift: int, length: int):
1190    a = []
1191    for _ in range(length):
1192        a.append( num & ((1 << num_bits_shift) - 1) )
1193        num = num >> num_bits_shift
1194    return tuple(a)
1195
1196def pack(z, num_bits_shift: int) -> int:
1197    limbs = (z.low, z.high)
1198    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1199
1200def pack_extended(z, num_bits_shift: int) -> int:
1201    limbs = (z.d0, z.d1, z.d2, z.d3)
1202    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1203
1204x = pack_extended(ids.x, num_bits_shift = 128)
1205div = pack(ids.div, num_bits_shift = 128)
1206
1207quotient, remainder = divmod(x, div)
1208
1209quotient_split = split(quotient, num_bits_shift=128, length=4)
1210
1211ids.quotient.d0 = quotient_split[0]
1212ids.quotient.d1 = quotient_split[1]
1213ids.quotient.d2 = quotient_split[2]
1214ids.quotient.d3 = quotient_split[3]
1215
1216remainder_split = split(remainder, num_bits_shift=128, length=2)
1217ids.remainder.low = remainder_split[0]
1218ids.remainder.high = remainder_split[1]"#}),
1219(EC_RECOVER_SUB_A_B, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
1220from starkware.python.math_utils import div_mod, safe_div
1221
1222a = pack(ids.a, PRIME)
1223b = pack(ids.b, PRIME)
1224
1225value = res = a - b"#}),
1226(A_B_BITAND_1, indoc! {r#"ids.a_lsb = ids.a & 1
1227ids.b_lsb = ids.b & 1"#}),
1228(EC_RECOVER_PRODUCT_MOD, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
1229from starkware.python.math_utils import div_mod, safe_div
1230
1231a = pack(ids.a, PRIME)
1232b = pack(ids.b, PRIME)
1233product = a * b
1234m = pack(ids.m, PRIME)
1235
1236value = res = product % m"#}),
1237(UINT256_MUL_INV_MOD_P, indoc! {r#"from starkware.python.math_utils import div_mod
1238
1239def split(a: int):
1240    return (a & ((1 << 128) - 1), a >> 128)
1241
1242def pack(z, num_bits_shift: int) -> int:
1243    limbs = (z.low, z.high)
1244    return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
1245
1246a = pack(ids.a, 128)
1247b = pack(ids.b, 128)
1248p = pack(ids.p, 128)
1249# For python3.8 and above the modular inverse can be computed as follows:
1250# b_inverse_mod_p = pow(b, -1, p)
1251# Instead we use the python3.7-friendly function div_mod from starkware.python.math_utils
1252b_inverse_mod_p = div_mod(1, b, p)
1253
1254b_inverse_mod_p_split = split(b_inverse_mod_p)
1255
1256ids.b_inverse_mod_p.low = b_inverse_mod_p_split[0]
1257ids.b_inverse_mod_p.high = b_inverse_mod_p_split[1]"#}),
1258(EC_RECOVER_PRODUCT_DIV_M, indoc! {r#"value = k = product // m"#}),
1259(SQUARE_SLOPE_X_MOD_P, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
1260
1261slope = pack(ids.slope, PRIME)
1262x0 = pack(ids.point0.x, PRIME)
1263x1 = pack(ids.point1.x, PRIME)
1264y0 = pack(ids.point0.y, PRIME)
1265
1266value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P"#}),
1267(SPLIT_XX, indoc! {r#"PRIME = 2**255 - 19
1268II = pow(2, (PRIME - 1) // 4, PRIME)
1269
1270xx = ids.xx.low + (ids.xx.high<<128)
1271x = pow(xx, (PRIME + 3) // 8, PRIME)
1272if (x * x - xx) % PRIME != 0:
1273    x = (x * II) % PRIME
1274if x % 2 != 0:
1275    x = PRIME - x
1276ids.x.low = x & ((1<<128)-1)
1277ids.x.high = x >> 128"#}),
1278(SKIP_NEXT_INSTRUCTION, indoc! {r#"skip_next_instruction()"#}, "test_utils"),
1279(PRINT_FELT, indoc! {r#"print(ids.x)"#}, "test_utils"),
1280(PRINT_ARR, indoc! {r#"print(bytes.fromhex(f"{ids.name:062x}").decode().replace('\x00',''))
1281arr = [memory[ids.arr + i] for i in range(ids.arr_len)]
1282print(arr)"#}, "test_utils"),
1283(PRINT_DICT, indoc! {r#"print(bytes.fromhex(f"{ids.name:062x}").decode().replace('\x00',''))
1284data = __dict_manager.get_dict(ids.dict_ptr)
1285print(
1286    {k: v if isinstance(v, int) else [memory[v + i] for i in range(ids.pointer_size)] for k, v in data.items()}
1287)"#}, "test_utils"),
1288(RUN_P_CIRCUIT, "from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner\nassert builtin_runners[\"add_mod_builtin\"].instance_def.batch_size == 1\nassert builtin_runners[\"mul_mod_builtin\"].instance_def.batch_size == 1\n\nModBuiltinRunner.fill_memory(\n    memory=memory,\n    add_mod=(ids.add_mod_ptr.address_, builtin_runners[\"add_mod_builtin\"], ids.add_mod_n),\n    mul_mod=(ids.mul_mod_ptr.address_, builtin_runners[\"mul_mod_builtin\"], ids.mul_mod_n),\n)"),
1289(RUN_P_CIRCUIT_WITH_LARGE_BATCH_SIZE, "from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner\nassert builtin_runners[\"add_mod_builtin\"].instance_def.batch_size == ids.BATCH_SIZE\nassert builtin_runners[\"mul_mod_builtin\"].instance_def.batch_size == ids.BATCH_SIZE\n\nModBuiltinRunner.fill_memory(\n    memory=memory,\n    add_mod=(ids.add_mod_ptr.address_, builtin_runners[\"add_mod_builtin\"], ids.add_mod_n),\n    mul_mod=(ids.mul_mod_ptr.address_, builtin_runners[\"mul_mod_builtin\"], ids.mul_mod_n),\n)"),
1290(NONDET_ELEMENTS_OVER_TEN, indoc! {r#"memory[ap] = to_felt_or_relocatable(ids.elements_end - ids.elements >= 10)"#}),
1291(NONDET_ELEMENTS_OVER_TWO, indoc! {r#"memory[ap] = to_felt_or_relocatable(ids.elements_end - ids.elements >= 2)"#}),
1292(EXCESS_BALANCE, indoc! {r#"from excess_balance import excess_balance_func
1293
1294res = excess_balance_func(ids, memory, __dict_manager)
1295
1296ids.check_account_value = res["account_value"]
1297ids.check_excess_balance = res["excess_balance"]
1298ids.check_margin_requirement_d = res["margin_requirement"]
1299ids.check_unrealized_pnl_d = res["unrealized_pnl"]"#})
1300}