1use crate::Felt252;
2use crate::{
3 hint_processor::builtin_hint_processor::hint_utils::{
4 get_integer_from_var_name, get_relocatable_from_var_name, insert_value_from_var_name,
5 insert_value_into_ap,
6 },
7 hint_processor::hint_processor_definition::HintReference,
8 math_utils::{isqrt, pow2_const, pow2_const_nz},
9 serde::deserialize_program::ApTracking,
10 stdlib::{
11 borrow::Cow,
12 boxed::Box,
13 collections::HashMap,
14 ops::{Shl, Shr},
15 prelude::*,
16 },
17 types::{errors::math_errors::MathError, relocatable::Relocatable},
18 vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
19};
20use num_bigint::BigUint;
21use num_integer::{div_rem, Integer};
22use num_traits::{One, Zero};
23
24pub(crate) struct Uint256<'a> {
26 pub low: Cow<'a, Felt252>,
27 pub high: Cow<'a, Felt252>,
28}
29
30impl<'a> Uint256<'a> {
31 pub(crate) fn from_base_addr(
32 addr: Relocatable,
33 name: &str,
34 vm: &'a VirtualMachine,
35 ) -> Result<Self, HintError> {
36 Ok(Self {
37 low: vm.get_integer(addr).map_err(|_| {
38 HintError::IdentifierHasNoMember(Box::new((name.to_string(), "low".to_string())))
39 })?,
40 high: vm.get_integer((addr + 1)?).map_err(|_| {
41 HintError::IdentifierHasNoMember(Box::new((name.to_string(), "high".to_string())))
42 })?,
43 })
44 }
45
46 pub(crate) fn from_var_name(
47 name: &str,
48 vm: &'a VirtualMachine,
49 ids_data: &HashMap<String, HintReference>,
50 ap_tracking: &ApTracking,
51 ) -> Result<Self, HintError> {
52 let base_addr = get_relocatable_from_var_name(name, vm, ids_data, ap_tracking)?;
53 Self::from_base_addr(base_addr, name, vm)
54 }
55
56 pub(crate) fn from_values(low: Felt252, high: Felt252) -> Self {
57 let low = Cow::Owned(low);
58 let high = Cow::Owned(high);
59 Self { low, high }
60 }
61
62 pub(crate) fn insert_from_var_name(
63 self,
64 var_name: &str,
65 vm: &mut VirtualMachine,
66 ids_data: &HashMap<String, HintReference>,
67 ap_tracking: &ApTracking,
68 ) -> Result<(), HintError> {
69 let addr = get_relocatable_from_var_name(var_name, vm, ids_data, ap_tracking)?;
70
71 vm.insert_value(addr, self.low.into_owned())?;
72 vm.insert_value((addr + 1)?, self.high.into_owned())?;
73
74 Ok(())
75 }
76
77 pub(crate) fn pack(self) -> BigUint {
78 (self.high.to_biguint() << 128) + self.low.to_biguint()
79 }
80
81 pub(crate) fn split(num: &BigUint) -> Self {
82 let mask_low: BigUint = u128::MAX.into();
83 let low = Felt252::from(&(num & mask_low));
84 let high = Felt252::from(&(num >> 128));
85 Self::from_values(low, high)
86 }
87}
88
89impl<'a> From<&BigUint> for Uint256<'a> {
90 fn from(value: &BigUint) -> Self {
91 Self::split(value)
92 }
93}
94
95impl<'a> From<Felt252> for Uint256<'a> {
96 fn from(value: Felt252) -> Self {
97 let (high, low) = value.div_rem(pow2_const_nz(128));
98 Self::from_values(low, high)
99 }
100}
101
102pub fn uint256_add(
116 vm: &mut VirtualMachine,
117 ids_data: &HashMap<String, HintReference>,
118 ap_tracking: &ApTracking,
119 low_only: bool,
120) -> Result<(), HintError> {
121 let shift = pow2_const(128);
122
123 let a = Uint256::from_var_name("a", vm, ids_data, ap_tracking)?;
124 let b = Uint256::from_var_name("b", vm, ids_data, ap_tracking)?;
125 let a_low = a.low.as_ref();
126 let b_low = b.low.as_ref();
127
128 let carry_low = Felt252::from((a_low + b_low >= shift) as u8);
132
133 if !low_only {
134 let a_high = a.high.as_ref();
135 let b_high = b.high.as_ref();
136
137 let carry_high = Felt252::from((a_high + b_high + carry_low >= shift) as u8);
141
142 insert_value_from_var_name("carry_high", carry_high, vm, ids_data, ap_tracking)?;
143 }
144
145 insert_value_from_var_name("carry_low", carry_low, vm, ids_data, ap_tracking)
146}
147
148pub fn uint128_add(
156 vm: &mut VirtualMachine,
157 ids_data: &HashMap<String, HintReference>,
158 ap_tracking: &ApTracking,
159) -> Result<(), HintError> {
160 let shift = pow2_const(128);
161 let a = get_integer_from_var_name("a", vm, ids_data, ap_tracking)?;
162 let b = get_integer_from_var_name("b", vm, ids_data, ap_tracking)?;
163 let a = a.as_ref();
164 let b = b.as_ref();
165
166 let carry = Felt252::from((a + b >= shift) as u8);
170
171 insert_value_from_var_name("carry", carry, vm, ids_data, ap_tracking)
172}
173
174pub fn uint256_sub(
198 vm: &mut VirtualMachine,
199 ids_data: &HashMap<String, HintReference>,
200 ap_tracking: &ApTracking,
201) -> Result<(), HintError> {
202 let a = Uint256::from_var_name("a", vm, ids_data, ap_tracking)?.pack();
203 let b = Uint256::from_var_name("b", vm, ids_data, ap_tracking)?.pack();
204
205 let res = if a >= b {
208 a - b
209 } else {
210 let mod_256 = BigUint::one() << 256;
216 if mod_256 >= b {
217 mod_256 - b + a
218 } else {
219 let lowered_b = b.mod_floor(&mod_256);
220 if a >= lowered_b {
222 a - lowered_b
223 } else {
224 mod_256 - lowered_b + a
225 }
226 }
227 };
228
229 let res = Uint256::split(&res);
230
231 res.insert_from_var_name("res", vm, ids_data, ap_tracking)
232}
233
234pub fn split_64(
242 vm: &mut VirtualMachine,
243 ids_data: &HashMap<String, HintReference>,
244 ap_tracking: &ApTracking,
245) -> Result<(), HintError> {
246 let a = get_integer_from_var_name("a", vm, ids_data, ap_tracking)?;
247 let digits = a.to_le_digits();
248 let mut bytes = [0u8; 32];
249 bytes[..8].copy_from_slice(digits[1].to_le_bytes().as_slice());
250 bytes[8..16].copy_from_slice(digits[2].to_le_bytes().as_slice());
251 bytes[16..24].copy_from_slice(digits[3].to_le_bytes().as_slice());
252
253 let low = Felt252::from(digits[0]);
254 let high = Felt252::from_bytes_le(&bytes);
255 insert_value_from_var_name("high", high, vm, ids_data, ap_tracking)?;
256 insert_value_from_var_name("low", low, vm, ids_data, ap_tracking)
257}
258
259pub fn uint256_sqrt(
271 vm: &mut VirtualMachine,
272 ids_data: &HashMap<String, HintReference>,
273 ap_tracking: &ApTracking,
274 only_low: bool,
275) -> Result<(), HintError> {
276 let n = Uint256::from_var_name("n", vm, ids_data, ap_tracking)?.pack();
277
278 let root = isqrt(&n)?;
287
288 if root.bits() > 128 {
289 return Err(HintError::AssertionFailed(
290 format!("assert 0 <= {} < 2 ** 128", &root).into_boxed_str(),
291 ));
292 }
293
294 let root = Felt252::from(&root);
295
296 if only_low {
297 insert_value_from_var_name("root", root, vm, ids_data, ap_tracking)?;
298 } else {
299 let root_u256 = Uint256::from_values(root, Felt252::ZERO);
300 root_u256.insert_from_var_name("root", vm, ids_data, ap_tracking)?;
301 }
302 Ok(())
303}
304
305pub fn uint256_signed_nn(
310 vm: &mut VirtualMachine,
311 ids_data: &HashMap<String, HintReference>,
312 ap_tracking: &ApTracking,
313) -> Result<(), HintError> {
314 let a_addr = get_relocatable_from_var_name("a", vm, ids_data, ap_tracking)?;
315 let a_high = vm.get_integer((a_addr + 1_usize)?)?;
316 let result: Felt252 =
319 if *a_high >= Felt252::ZERO && a_high.as_ref() <= &Felt252::from(i128::MAX) {
320 Felt252::ONE
321 } else {
322 Felt252::ZERO
323 };
324 insert_value_into_ap(vm, result)
325}
326
327pub fn uint256_unsigned_div_rem(
341 vm: &mut VirtualMachine,
342 ids_data: &HashMap<String, HintReference>,
343 ap_tracking: &ApTracking,
344) -> Result<(), HintError> {
345 uint256_offseted_unsigned_div_rem(vm, ids_data, ap_tracking, 0, 1)
346}
347
348pub fn uint256_expanded_unsigned_div_rem(
362 vm: &mut VirtualMachine,
363 ids_data: &HashMap<String, HintReference>,
364 ap_tracking: &ApTracking,
365) -> Result<(), HintError> {
366 uint256_offseted_unsigned_div_rem(vm, ids_data, ap_tracking, 1, 3)
367}
368
369pub fn uint256_offseted_unsigned_div_rem(
370 vm: &mut VirtualMachine,
371 ids_data: &HashMap<String, HintReference>,
372 ap_tracking: &ApTracking,
373 div_offset_low: usize,
374 div_offset_high: usize,
375) -> Result<(), HintError> {
376 let a = Uint256::from_var_name("a", vm, ids_data, ap_tracking)?;
377 let a_low = a.low.as_ref();
378 let a_high = a.high.as_ref();
379
380 let div_addr = get_relocatable_from_var_name("div", vm, ids_data, ap_tracking)?;
381 let div_low = vm.get_integer((div_addr + div_offset_low)?)?;
382 let div_high = vm.get_integer((div_addr + div_offset_high)?)?;
383 let div_low = div_low.as_ref();
384 let div_high = div_high.as_ref();
385
386 let a = (a_high.to_biguint() << 128_u32) + a_low.to_biguint();
397 let div = (div_high.to_biguint() << 128_u32) + div_low.to_biguint();
398 let (quotient, remainder) = div_rem(a, div);
401
402 let quotient = Uint256::from("ient);
403 let remainder = Uint256::from(&remainder);
404
405 quotient.insert_from_var_name("quotient", vm, ids_data, ap_tracking)?;
406 remainder.insert_from_var_name("remainder", vm, ids_data, ap_tracking)?;
407
408 Ok(())
409}
410
411pub fn uint256_mul_div_mod(
427 vm: &mut VirtualMachine,
428 ids_data: &HashMap<String, HintReference>,
429 ap_tracking: &ApTracking,
430) -> Result<(), HintError> {
431 let a_addr = get_relocatable_from_var_name("a", vm, ids_data, ap_tracking)?;
433 let b_addr = get_relocatable_from_var_name("b", vm, ids_data, ap_tracking)?;
434 let div_addr = get_relocatable_from_var_name("div", vm, ids_data, ap_tracking)?;
435 let quotient_low_addr =
436 get_relocatable_from_var_name("quotient_low", vm, ids_data, ap_tracking)?;
437 let quotient_high_addr =
438 get_relocatable_from_var_name("quotient_high", vm, ids_data, ap_tracking)?;
439 let remainder_addr = get_relocatable_from_var_name("remainder", vm, ids_data, ap_tracking)?;
440
441 let a_low = vm.get_integer(a_addr)?;
442 let a_high = vm.get_integer((a_addr + 1_usize)?)?;
443 let b_low = vm.get_integer(b_addr)?;
444 let b_high = vm.get_integer((b_addr + 1_usize)?)?;
445 let div_low = vm.get_integer(div_addr)?;
446 let div_high = vm.get_integer((div_addr + 1_usize)?)?;
447 let a_low = a_low.as_ref();
448 let a_high = a_high.as_ref();
449 let b_low = b_low.as_ref();
450 let b_high = b_high.as_ref();
451 let div_low = div_low.as_ref();
452 let div_high = div_high.as_ref();
453
454 let a = a_high.to_biguint().shl(128_usize) + a_low.to_biguint();
456 let b = b_high.to_biguint().shl(128_usize) + b_low.to_biguint();
457 let div = div_high.to_biguint().shl(128_usize) + div_low.to_biguint();
458 if div.is_zero() {
459 return Err(MathError::DividedByZero.into());
460 }
461 let (quotient, remainder) = (a * b).div_mod_floor(&div);
462
463 vm.insert_value(
465 quotient_low_addr,
466 Felt252::from(&("ient & &BigUint::from(u128::MAX))),
467 )?;
468 vm.insert_value(
470 (quotient_low_addr + 1)?,
471 Felt252::from(&(("ient).shr(128_u32) & &BigUint::from(u128::MAX))),
472 )?;
473 vm.insert_value(
475 quotient_high_addr,
476 Felt252::from(&(("ient).shr(256_u32) & &BigUint::from(u128::MAX))),
477 )?;
478 vm.insert_value(
480 (quotient_high_addr + 1)?,
481 Felt252::from(&(("ient).shr(384_u32))),
482 )?;
483 vm.insert_value(
485 remainder_addr,
486 Felt252::from(&(&remainder & &BigUint::from(u128::MAX))),
487 )?;
488 vm.insert_value(
490 (remainder_addr + 1)?,
491 Felt252::from(&remainder.shr(128_u32)),
492 )?;
493
494 Ok(())
495}
496
497#[cfg(test)]
498mod tests {
499 use super::*;
500 use crate::felt_str;
501 use crate::{
502 any_box,
503 hint_processor::{
504 builtin_hint_processor::{
505 builtin_hint_processor_definition::{BuiltinHintProcessor, HintProcessorData},
506 hint_code,
507 },
508 hint_processor_definition::HintProcessorLogic,
509 },
510 types::relocatable::{MaybeRelocatable, Relocatable},
511 utils::test_utils::*,
512 vm::{errors::memory_errors::MemoryError, vm_core::VirtualMachine},
513 };
514 use assert_matches::assert_matches;
515
516 #[cfg(target_arch = "wasm32")]
517 use wasm_bindgen_test::*;
518
519 #[test]
520 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
521 fn run_uint256_add_ok() {
522 let hint_code = hint_code::UINT256_ADD;
523 let mut vm = vm_with_range_check!();
524 vm.run_context.fp = 10;
526 let ids_data =
528 non_continuous_ids_data![("a", -6), ("b", -4), ("carry_low", 2), ("carry_high", 3)];
529 vm.segments = segments![
530 ((1, 4), 2),
531 ((1, 5), 3),
532 ((1, 6), 4),
533 ((1, 7), ("340282366920938463463374607431768211455", 10))
534 ];
535 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
537 check_memory![vm.segments.memory, ((1, 12), 0), ((1, 13), 1)];
539 }
540
541 #[test]
542 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
543 fn run_uint256_add_low_only_ok() {
544 let hint_code =
545 "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0";
546 let mut vm = vm_with_range_check!();
547 vm.run_context.fp = 10;
549 let ids_data = non_continuous_ids_data![("a", -6), ("b", -4), ("carry_low", 2)];
551 vm.segments = segments![
552 ((1, 4), 2),
553 ((1, 5), 3),
554 ((1, 6), 4),
555 ((1, 7), ("340282366920938463463374607431768211455", 10))
556 ];
557 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
559 check_memory![vm.segments.memory, ((1, 12), 0)];
561 }
562
563 #[test]
564 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
565 fn run_uint128_add_ok() {
566 let hint_code = hint_code::UINT128_ADD;
567 let mut vm = vm_with_range_check!();
568 vm.run_context.fp = 0;
570 let ids_data = non_continuous_ids_data![("a", 0), ("b", 1), ("carry", 2)];
572 vm.segments = segments![
573 ((1, 0), 180141183460469231731687303715884105727_u128),
574 ((1, 1), 180141183460469231731687303715884105727_u128),
575 ];
576 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
578 check_memory![vm.segments.memory, ((1, 2), 1)];
580 }
581
582 #[test]
583 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
584 fn run_uint256_add_fail_inserts() {
585 let hint_code = hint_code::UINT256_ADD;
586 let mut vm = vm_with_range_check!();
587 vm.run_context.fp = 10;
589 let ids_data =
591 non_continuous_ids_data![("a", -6), ("b", -4), ("carry_high", 3), ("carry_low", 2)];
592 vm.segments = segments![
594 ((1, 4), 2),
595 ((1, 5), 3),
596 ((1, 6), 4),
597 ((1, 7), 2),
598 ((1, 12), 2)
599 ];
600 assert_matches!(
602 run_hint!(vm, ids_data, hint_code),
603 Err(HintError::Memory(
604 MemoryError::InconsistentMemory(bx)
605 )) if *bx == (Relocatable::from((1, 12)),
606 MaybeRelocatable::from(Felt252::from(2)),
607 MaybeRelocatable::from(Felt252::ZERO))
608 );
609 }
610
611 #[test]
612 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
613 fn run_uint256_sub_nonnegative_ok() {
614 let hint_code = hint_code::UINT256_SUB;
615 let mut vm = vm_with_range_check!();
616 vm.run_context.fp = 0;
618 let ids_data = non_continuous_ids_data![("a", 0), ("b", 2), ("res", 4)];
620 vm.segments = segments![
621 ((1, 0), 12179),
622 ((1, 1), 13044),
623 ((1, 2), 1001),
624 ((1, 3), 6687),
625 ];
626 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
628 check_memory![vm.segments.memory, ((1, 4), 11178), ((1, 5), 6357)];
630 }
631
632 #[test]
633 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
634 fn run_uint256_sub_negative_ok() {
635 let hint_code = hint_code::UINT256_SUB;
636 let mut vm = vm_with_range_check!();
637 vm.run_context.fp = 0;
639 let ids_data = non_continuous_ids_data![("a", 0), ("b", 2), ("res", 4)];
641 vm.segments = segments![
642 ((1, 0), 1001),
643 ((1, 1), 6687),
644 ((1, 2), 12179),
645 ((1, 3), 13044),
646 ];
647 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
649 check_memory![
651 vm.segments.memory,
652 ((1, 4), ("340282366920938463463374607431768200278", 10)),
653 ((1, 5), ("340282366920938463463374607431768205098", 10))
654 ];
655 }
656
657 #[test]
658 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
659 fn run_uint256_sub_b_high_gt_256_lte_a() {
660 let hint_code = hint_code::UINT256_SUB;
661 let mut vm = vm_with_range_check!();
662 vm.run_context.fp = 0;
664 let ids_data = non_continuous_ids_data![("a", 0), ("b", 2), ("res", 4)];
666 vm.segments = segments![
667 ((1, 0), ("340282366920938463463374607431768211456", 10)),
668 ((1, 1), 0),
669 ((1, 2), 0),
670 ((1, 3), ("340282366920938463463374607431768211457", 10)),
671 ];
672 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
674 check_memory![vm.segments.memory, ((1, 4), 0), ((1, 5), 0)];
676 }
677
678 #[test]
679 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
680 fn run_uint256_sub_b_high_gt_256_gt_a() {
681 let hint_code = hint_code::UINT256_SUB;
682 let mut vm = vm_with_range_check!();
683 vm.run_context.fp = 0;
685 let ids_data = non_continuous_ids_data![("a", 0), ("b", 2), ("res", 4)];
687 vm.segments = segments![
688 ((1, 0), 1),
689 ((1, 1), 0),
690 ((1, 2), 0),
691 ((1, 3), ("340282366920938463463374607431768211457", 10)),
692 ];
693 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
695 check_memory![
697 vm.segments.memory,
698 ((1, 4), ("1", 10)),
699 ((1, 5), ("340282366920938463463374607431768211455", 10))
700 ];
701 }
702
703 #[test]
704 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
705 fn run_uint256_sub_missing_member() {
706 let hint_code = hint_code::UINT256_SUB;
707 let mut vm = vm_with_range_check!();
708 vm.run_context.fp = 0;
710 let ids_data = non_continuous_ids_data![("a", 0)];
712 assert_matches!(run_hint!(vm, ids_data.clone(), hint_code),
714 Err(HintError::IdentifierHasNoMember(bx)) if *bx == ("a".to_string(), "low".to_string())
715 );
716 vm.segments = segments![((1, 0), 1001)];
717 assert_matches!(run_hint!(vm, ids_data, hint_code),
719 Err(HintError::IdentifierHasNoMember(bx)) if *bx == ("a".to_string(), "high".to_string())
720 );
721 }
722
723 #[test]
724 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
725 fn run_split_64_ok() {
726 let hint_code = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64";
727 let mut vm = vm_with_range_check!();
728 vm.run_context.fp = 10;
730 let ids_data = non_continuous_ids_data![("a", -3), ("high", 1), ("low", 0)];
732 vm.segments = segments![((1, 7), ("850981239023189021389081239089023", 10))];
734 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
736 check_memory![
739 vm.segments.memory,
740 ((1, 10), 7249717543555297151_u64),
741 ((1, 11), 46131785404667_u64)
742 ];
743 }
744
745 #[test]
746 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
747 fn run_split_64_with_big_a() {
748 let hint_code = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64";
749 let mut vm = vm_with_range_check!();
750 vm.run_context.fp = 10;
752 let ids_data = non_continuous_ids_data![("a", -3), ("high", 1), ("low", 0)];
754 vm.segments = segments![((1, 7), ("400066369019890261321163226850167045262", 10))];
756 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
758
759 check_memory![
762 vm.segments.memory,
763 ((1, 10), 2279400676465785998_u64),
764 ((1, 11), 21687641321487626429_u128)
765 ];
766 }
767
768 #[test]
769 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
770 fn run_split_64_memory_error() {
771 let hint_code = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64";
772 let mut vm = vm_with_range_check!();
773 vm.run_context.fp = 10;
775 let ids_data = non_continuous_ids_data![("a", -3), ("high", 1), ("low", 0)];
777 vm.segments = segments![
779 ((1, 7), ("850981239023189021389081239089023", 10)),
780 ((1, 10), 0)
781 ];
782 assert_matches!(
784 run_hint!(vm, ids_data, hint_code),
785 Err(HintError::Memory(
786 MemoryError::InconsistentMemory(bx)
787 )) if *bx == (Relocatable::from((1, 10)),
788 MaybeRelocatable::from(Felt252::ZERO),
789 MaybeRelocatable::from(felt_str!("7249717543555297151")))
790 );
791 }
792
793 #[test]
794 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
795 fn run_uint256_sqrt_ok() {
796 let hint_code = hint_code::UINT256_SQRT;
797 let mut vm = vm_with_range_check!();
798 vm.run_context.fp = 5;
800 let ids_data = non_continuous_ids_data![("n", -5), ("root", 0)];
802 vm.segments = segments![((1, 0), 17), ((1, 1), 7)];
803 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
805 check_memory![
808 vm.segments.memory,
809 ((1, 5), 48805497317890012913_u128),
810 ((1, 6), 0)
811 ];
812 }
813
814 #[test]
815 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
816 fn run_uint256_sqrt_felt_ok() {
817 let hint_code = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root = root";
818 let mut vm = vm_with_range_check!();
819 vm.run_context.fp = 0;
821 let ids_data = non_continuous_ids_data![("n", 0), ("root", 2)];
823 vm.segments = segments![((1, 0), 879232), ((1, 1), 135906)];
824 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
826 check_memory![vm.segments.memory, ((1, 2), 6800471701195223914689)];
829 }
830
831 #[test]
832 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
833 fn run_uint256_sqrt_assert_error() {
834 let hint_code = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root.low = root\nids.root.high = 0";
835 let mut vm = vm_with_range_check!();
836 vm.run_context.fp = 5;
838 let ids_data = non_continuous_ids_data![("n", -5), ("root", 0)];
840 vm.segments = segments![
841 ((1, 0), 0),
842 ((1, 1), ("340282366920938463463374607431768211458", 10))
843 ];
844 assert_matches!(
846 run_hint!(vm, ids_data, hint_code),
847 Err(HintError::AssertionFailed(bx)) if bx.as_ref() == "assert 0 <= 340282366920938463463374607431768211456 < 2 ** 128"
848 );
849 }
850
851 #[test]
852 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
853 fn run_uint256_invalid_memory_insert() {
854 let hint_code = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root.low = root\nids.root.high = 0";
855 let mut vm = vm_with_range_check!();
856 vm.run_context.fp = 5;
858 let ids_data = non_continuous_ids_data![("n", -5), ("root", 0)];
860 vm.segments = segments![((1, 0), 17), ((1, 1), 7), ((1, 5), 1)];
862 assert_matches!(
864 run_hint!(vm, ids_data, hint_code),
865 Err(HintError::Memory(
866 MemoryError::InconsistentMemory(bx)
867 )) if *bx == (Relocatable::from((1, 5)),
868 MaybeRelocatable::from(Felt252::ONE),
869 MaybeRelocatable::from(felt_str!("48805497317890012913")))
870 );
871 }
872
873 #[test]
874 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
875 fn run_signed_nn_ok_result_one() {
876 let hint_code = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0";
877 let mut vm = vm_with_range_check!();
878 run_context!(vm, 0, 5, 4);
880 let ids_data = non_continuous_ids_data![("a", -4)];
882 vm.segments = segments![(
884 (1, 1),
885 (
886 "3618502788666131213697322783095070105793248398792065931704779359851756126208",
887 10
888 )
889 )];
890 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
892 check_memory![vm.segments.memory, ((1, 5), 1)];
895 }
896
897 #[test]
898 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
899 fn run_signed_nn_ok_result_zero() {
900 let hint_code = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0";
901 let mut vm = vm_with_range_check!();
902 run_context!(vm, 0, 5, 4);
904 let ids_data = non_continuous_ids_data![("a", -4)];
906 vm.segments = segments![(
908 (1, 1),
909 (
910 "3618502788666131213697322783095070105793248398792065931704779359851756126209",
911 10
912 )
913 )];
914 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
916 check_memory![vm.segments.memory, ((1, 5), 0)];
919 }
920
921 #[test]
922 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
923 fn run_signed_nn_ok_invalid_memory_insert() {
924 let hint_code = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0";
925 let mut vm = vm_with_range_check!();
926 run_context!(vm, 0, 5, 4);
928 let ids_data = non_continuous_ids_data![("a", -4)];
930 vm.segments = segments![((1, 1), 1), ((1, 5), 55)];
931 assert_matches!(
933 run_hint!(vm, ids_data, hint_code),
934 Err(HintError::Memory(
935 MemoryError::InconsistentMemory(bx)
936 )) if *bx == (Relocatable::from((1, 5)),
937 MaybeRelocatable::from(Felt252::from(55)),
938 MaybeRelocatable::from(Felt252::ONE))
939 );
940 }
941
942 #[test]
943 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
944 fn run_unsigned_div_rem_ok() {
945 let hint_code = hint_code::UINT256_UNSIGNED_DIV_REM;
946 let mut vm = vm_with_range_check!();
947 vm.run_context.fp = 10;
949 let ids_data =
951 non_continuous_ids_data![("a", -6), ("div", -4), ("quotient", 0), ("remainder", 2)];
952 vm.segments = segments![((1, 4), 89), ((1, 5), 72), ((1, 6), 3), ((1, 7), 7)];
954 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
956 check_memory![
959 vm.segments.memory,
960 ((1, 10), 10),
961 ((1, 11), 0),
962 ((1, 12), 59),
963 ((1, 13), 2)
964 ];
965 }
966
967 #[test]
968 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
969 fn run_unsigned_div_rem_expanded_ok() {
970 let hint_code = hint_code::UINT256_EXPANDED_UNSIGNED_DIV_REM;
971 let mut vm = vm_with_range_check!();
972 vm.run_context.fp = 0;
974 let ids_data =
976 non_continuous_ids_data![("a", 0), ("div", 2), ("quotient", 7), ("remainder", 9)];
977 vm.segments = segments![
979 ((1, 0), 89),
981 ((1, 1), 72),
982 ((1, 2), 55340232221128654848),
984 ((1, 3), 3),
985 ((1, 4), 129127208515966861312),
986 ((1, 5), 7),
987 ((1, 6), 0),
988 ];
989 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
991 check_memory![
994 vm.segments.memory,
995 ((1, 7), 10),
996 ((1, 8), 0),
997 ((1, 9), 59),
998 ((1, 10), 2),
999 ];
1000 }
1001
1002 #[test]
1003 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1004 fn run_unsigned_div_rem_invalid_memory_insert() {
1005 let hint_code = hint_code::UINT256_UNSIGNED_DIV_REM;
1006 let mut vm = vm_with_range_check!();
1007 vm.run_context.fp = 10;
1009 let ids_data =
1011 non_continuous_ids_data![("a", -6), ("div", -4), ("quotient", 0), ("remainder", 2)];
1012 vm.segments = segments![
1014 ((1, 4), 89),
1015 ((1, 5), 72),
1016 ((1, 6), 3),
1017 ((1, 7), 7),
1018 ((1, 10), 0)
1019 ];
1020 assert_matches!(
1022 run_hint!(vm, ids_data, hint_code),
1023 Err(HintError::Memory(
1024 MemoryError::InconsistentMemory(bx)
1025 )) if *bx == (Relocatable::from((1, 10)),
1026 MaybeRelocatable::from(Felt252::ZERO),
1027 MaybeRelocatable::from(Felt252::from(10)))
1028 );
1029 }
1030
1031 #[test]
1032 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1033 fn run_unsigned_div_rem_invalid_memory_insert_2() {
1034 let hint_code = hint_code::UINT256_UNSIGNED_DIV_REM;
1035 let mut vm = vm_with_range_check!();
1036 vm.run_context.fp = 10;
1038 let ids_data =
1040 non_continuous_ids_data![("a", -6), ("div", -4), ("quotient", 0), ("remainder", 2)];
1041 vm.segments = segments![
1043 ((1, 4), 89),
1044 ((1, 5), 72),
1045 ((1, 6), 3),
1046 ((1, 7), 7),
1047 ((1, 11), 1)
1048 ];
1049 assert_matches!(
1051 run_hint!(vm, ids_data, hint_code),
1052 Err(HintError::Memory(
1053 MemoryError::InconsistentMemory(bx)
1054 )) if *bx == (Relocatable::from((1, 11)),
1055 MaybeRelocatable::from(Felt252::ONE),
1056 MaybeRelocatable::from(Felt252::ZERO))
1057 );
1058 }
1059
1060 #[test]
1061 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1062 fn run_mul_div_mod_ok() {
1063 let mut vm = vm_with_range_check!();
1064 vm.run_context.fp = 10;
1066 let ids_data = non_continuous_ids_data![
1068 ("a", -8),
1069 ("b", -6),
1070 ("div", -4),
1071 ("quotient_low", 0),
1072 ("quotient_high", 2),
1073 ("remainder", 4)
1074 ];
1075 vm.segments = segments![
1077 ((1, 2), 89),
1078 ((1, 3), 72),
1079 ((1, 4), 3),
1080 ((1, 5), 7),
1081 ((1, 6), 107),
1082 ((1, 7), 114)
1083 ];
1084 assert_matches!(
1086 run_hint!(vm, ids_data, hint_code::UINT256_MUL_DIV_MOD),
1087 Ok(())
1088 );
1089 check_memory![
1092 vm.segments.memory,
1093 ((1, 10), 143276786071974089879315624181797141668),
1094 ((1, 11), 4),
1095 ((1, 12), 0),
1096 ((1, 13), 0),
1097 ((1, 15), 101)
1099 ];
1100 assert_eq!(
1101 vm.segments
1102 .memory
1103 .get_integer((1, 14).into())
1104 .unwrap()
1105 .as_ref(),
1106 &felt_str!("322372768661941702228460154409043568767")
1107 )
1108 }
1109
1110 #[test]
1111 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1112 fn run_mul_div_mod_missing_ids() {
1113 let mut vm = vm_with_range_check!();
1114 vm.run_context.fp = 10;
1116 let ids_data = non_continuous_ids_data![
1118 ("a", -8),
1119 ("b", -6),
1120 ("div", -4),
1121 ("quotient", 0),
1122 ("remainder", 2)
1123 ];
1124 vm.segments = segments![
1126 ((1, 2), 89),
1127 ((1, 3), 72),
1128 ((1, 4), 3),
1129 ((1, 5), 7),
1130 ((1, 6), 107),
1131 ((1, 7), 114)
1132 ];
1133 assert_matches!(
1135 run_hint!(vm, ids_data, hint_code::UINT256_MUL_DIV_MOD),
1136 Err(HintError::UnknownIdentifier(bx)) if bx.as_ref() == "quotient_low"
1137 );
1138 }
1139}