cairo_vm/hint_processor/builtin_hint_processor/
uint384.rs

1use crate::Felt252;
2use num_bigint::BigUint;
3use num_integer::Integer;
4use num_traits::Zero;
5
6use crate::math_utils::isqrt;
7use crate::stdlib::{boxed::Box, collections::HashMap, prelude::*};
8use crate::types::errors::math_errors::MathError;
9use crate::{
10    hint_processor::hint_processor_definition::HintReference,
11    math_utils::pow2_const_nz,
12    serde::deserialize_program::ApTracking,
13    vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
14};
15
16use super::hint_utils::{
17    get_constant_from_var_name, get_integer_from_var_name, get_relocatable_from_var_name,
18    insert_value_from_var_name, insert_value_into_ap,
19};
20use super::secp::bigint_utils::Uint384;
21// Notes: Hints in this lib use the type Uint384, which is equal to common lib's BigInt3
22
23/* Implements Hint:
24%{
25    def split(num: int, num_bits_shift: int, length: int):
26        a = []
27        for _ in range(length):
28            a.append( num & ((1 << num_bits_shift) - 1) )
29            num = num >> num_bits_shift
30        return tuple(a)
31
32    def pack(z, num_bits_shift: int) -> int:
33        limbs = (z.d0, z.d1, z.d2)
34        return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
35
36    a = pack(ids.a, num_bits_shift = 128)
37    div = pack(ids.div, num_bits_shift = 128)
38    quotient, remainder = divmod(a, div)
39
40    quotient_split = split(quotient, num_bits_shift=128, length=3)
41    assert len(quotient_split) == 3
42
43    ids.quotient.d0 = quotient_split[0]
44    ids.quotient.d1 = quotient_split[1]
45    ids.quotient.d2 = quotient_split[2]
46
47    remainder_split = split(remainder, num_bits_shift=128, length=3)
48    ids.remainder.d0 = remainder_split[0]
49    ids.remainder.d1 = remainder_split[1]
50    ids.remainder.d2 = remainder_split[2]
51%}
52*/
53pub fn uint384_unsigned_div_rem(
54    vm: &mut VirtualMachine,
55    ids_data: &HashMap<String, HintReference>,
56    ap_tracking: &ApTracking,
57) -> Result<(), HintError> {
58    let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?.pack();
59    let div = Uint384::from_var_name("div", vm, ids_data, ap_tracking)?.pack();
60
61    if div.is_zero() {
62        return Err(MathError::DividedByZero.into());
63    }
64    let (quotient, remainder) = a.div_mod_floor(&div);
65
66    let quotient_split = Uint384::split(&quotient);
67    quotient_split.insert_from_var_name("quotient", vm, ids_data, ap_tracking)?;
68
69    let remainder_split = Uint384::split(&remainder);
70    remainder_split.insert_from_var_name("remainder", vm, ids_data, ap_tracking)
71}
72
73/* Implements Hint:
74    %{
75        ids.low = ids.a & ((1<<128) - 1)
76        ids.high = ids.a >> 128
77    %}
78*/
79pub fn uint384_split_128(
80    vm: &mut VirtualMachine,
81    ids_data: &HashMap<String, HintReference>,
82    ap_tracking: &ApTracking,
83) -> Result<(), HintError> {
84    let bound = pow2_const_nz(128);
85    let a = get_integer_from_var_name("a", vm, ids_data, ap_tracking)?;
86    let (high, low) = a.div_rem(bound);
87    insert_value_from_var_name("low", low, vm, ids_data, ap_tracking)?;
88    insert_value_from_var_name("high", high, vm, ids_data, ap_tracking)
89}
90
91/* Implements Hint:
92%{
93    sum_d0 = ids.a.d0 + ids.b.d0
94    ids.carry_d0 = 1 if sum_d0 >= ids.SHIFT else 0
95    sum_d1 = ids.a.d1 + ids.b.d1 + ids.carry_d0
96    ids.carry_d1 = 1 if sum_d1 >= ids.SHIFT else 0
97    sum_d2 = ids.a.d2 + ids.b.d2 + ids.carry_d1
98    ids.carry_d2 = 1 if sum_d2 >= ids.SHIFT else 0
99%}
100 */
101pub fn add_no_uint384_check(
102    vm: &mut VirtualMachine,
103    ids_data: &HashMap<String, HintReference>,
104    ap_tracking: &ApTracking,
105    constants: &HashMap<String, Felt252>,
106) -> Result<(), HintError> {
107    let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?;
108    let b = Uint384::from_var_name("b", vm, ids_data, ap_tracking)?;
109    // This hint is not from the cairo commonlib, and its lib can be found under different paths, so we cant rely on a full path name
110    let shift = get_constant_from_var_name("SHIFT", constants)?.to_biguint();
111
112    let sum_d0 = (a.limbs[0].as_ref().to_biguint()) + (b.limbs[0].as_ref().to_biguint());
113    let carry_d0 = BigUint::from((sum_d0 >= shift) as usize);
114    let sum_d1 =
115        (a.limbs[1].as_ref().to_biguint()) + (b.limbs[1].as_ref().to_biguint()) + &carry_d0;
116    let carry_d1 = BigUint::from((sum_d1 >= shift) as usize);
117    let sum_d2 =
118        (a.limbs[2].as_ref().to_biguint()) + (b.limbs[2].as_ref().to_biguint()) + &carry_d1;
119    let carry_d2 = Felt252::from((sum_d2 >= shift) as usize);
120
121    insert_value_from_var_name(
122        "carry_d0",
123        Felt252::from(&carry_d0),
124        vm,
125        ids_data,
126        ap_tracking,
127    )?;
128    insert_value_from_var_name(
129        "carry_d1",
130        Felt252::from(&carry_d1),
131        vm,
132        ids_data,
133        ap_tracking,
134    )?;
135    insert_value_from_var_name("carry_d2", carry_d2, vm, ids_data, ap_tracking)
136}
137
138/* Implements Hint
139%{
140    from starkware.python.math_utils import isqrt
141
142    def split(num: int, num_bits_shift: int, length: int):
143        a = []
144        for _ in range(length):
145            a.append( num & ((1 << num_bits_shift) - 1) )
146            num = num >> num_bits_shift
147        return tuple(a)
148
149    def pack(z, num_bits_shift: int) -> int:
150        limbs = (z.d0, z.d1, z.d2)
151        return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
152
153    a = pack(ids.a, num_bits_shift=128)
154    root = isqrt(a)
155    assert 0 <= root < 2 ** 192
156    root_split = split(root, num_bits_shift=128, length=3)
157    ids.root.d0 = root_split[0]
158    ids.root.d1 = root_split[1]
159    ids.root.d2 = root_split[2]
160%}
161 */
162pub fn uint384_sqrt(
163    vm: &mut VirtualMachine,
164    ids_data: &HashMap<String, HintReference>,
165    ap_tracking: &ApTracking,
166) -> Result<(), HintError> {
167    let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?.pack();
168
169    let root = isqrt(&a)?;
170
171    if root.is_zero() || root.bits() > 192 {
172        return Err(HintError::AssertionFailed(
173            "assert 0 <= root < 2 ** 192".to_string().into_boxed_str(),
174        ));
175    }
176    let root_split = Uint384::split(&root);
177    root_split.insert_from_var_name("root", vm, ids_data, ap_tracking)
178}
179
180/* Implements Hint:
181   memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0
182*/
183pub fn uint384_signed_nn(
184    vm: &mut VirtualMachine,
185    ids_data: &HashMap<String, HintReference>,
186    ap_tracking: &ApTracking,
187) -> Result<(), HintError> {
188    let a_addr = get_relocatable_from_var_name("a", vm, ids_data, ap_tracking)?;
189    let a_d2 = vm.get_integer((a_addr + 2)?).map_err(|_| {
190        HintError::IdentifierHasNoMember(Box::new(("a".to_string(), "d2".to_string())))
191    })?;
192    let res = Felt252::from((a_d2.bits() <= 127) as u32);
193    insert_value_into_ap(vm, res)
194}
195
196/* Implements Hint:
197%{
198    def split(num: int, num_bits_shift: int, length: int):
199        a = []
200        for _ in range(length):
201        a.append( num & ((1 << num_bits_shift) - 1) )
202        num = num >> num_bits_shift
203        return tuple(a)
204
205    def pack(z, num_bits_shift: int) -> int:
206        limbs = (z.d0, z.d1, z.d2)
207        return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
208
209    a = pack(ids.a, num_bits_shift = 128)
210    b = pack(ids.b, num_bits_shift = 128)
211    p = pack(ids.p, num_bits_shift = 128)
212
213    res = (a - b) % p
214
215
216    res_split = split(res, num_bits_shift=128, length=3)
217
218    ids.res.d0 = res_split[0]
219    ids.res.d1 = res_split[1]
220    ids.res.d2 = res_split[2]
221%}
222*/
223pub fn sub_reduced_a_and_reduced_b(
224    vm: &mut VirtualMachine,
225    ids_data: &HashMap<String, HintReference>,
226    ap_tracking: &ApTracking,
227) -> Result<(), HintError> {
228    let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?.pack();
229    let b = Uint384::from_var_name("b", vm, ids_data, ap_tracking)?.pack();
230    let p = Uint384::from_var_name("p", vm, ids_data, ap_tracking)?.pack();
231    let res = if a > b {
232        (a - b).mod_floor(&p)
233    } else {
234        &p - (b - &a).mod_floor(&p)
235    };
236
237    let res_split = Uint384::split(&res);
238    res_split.insert_from_var_name("res", vm, ids_data, ap_tracking)
239}
240
241#[cfg(test)]
242mod tests {
243    use super::*;
244    use crate::hint_processor::builtin_hint_processor::hint_code;
245
246    use crate::felt_str;
247    use crate::{
248        any_box,
249        hint_processor::{
250            builtin_hint_processor::builtin_hint_processor_definition::{
251                BuiltinHintProcessor, HintProcessorData,
252            },
253            hint_processor_definition::HintProcessorLogic,
254        },
255        types::relocatable::{MaybeRelocatable, Relocatable},
256        utils::test_utils::*,
257        vm::{errors::memory_errors::MemoryError, vm_core::VirtualMachine},
258    };
259    use assert_matches::assert_matches;
260
261    #[cfg(target_arch = "wasm32")]
262    use wasm_bindgen_test::*;
263
264    #[test]
265    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
266    fn run_unsigned_div_rem_ok() {
267        let mut vm = vm_with_range_check!();
268        //Initialize fp
269        vm.run_context.fp = 10;
270        //Create hint_data
271        let ids_data =
272            non_continuous_ids_data![("a", -9), ("div", -6), ("quotient", -3), ("remainder", 0)];
273        //Insert ids into memory
274        vm.segments = segments![
275            //a
276            ((1, 1), 83434123481193248),
277            ((1, 2), 82349321849739284),
278            ((1, 3), 839243219401320423),
279            //div
280            ((1, 4), 9283430921839492319493),
281            ((1, 5), 313248123482483248),
282            ((1, 6), 3790328402913840)
283        ];
284        //Execute the hint
285        assert_matches!(
286            run_hint!(vm, ids_data, hint_code::UINT384_UNSIGNED_DIV_REM),
287            Ok(())
288        );
289        //Check hint memory inserts
290        check_memory![
291            vm.segments.memory,
292            // quotient
293            ((1, 7), 221),
294            ((1, 8), 0),
295            ((1, 9), 0),
296            // remainder
297            //((1, 10), 340282366920936411825224315027446796751),
298            //((1, 11), 340282366920938463394229121463989152931),
299            ((1, 12), 1580642357361782)
300        ];
301        assert_eq!(
302            vm.segments
303                .memory
304                .get_integer((1, 10).into())
305                .unwrap()
306                .as_ref(),
307            &felt_str!("340282366920936411825224315027446796751")
308        );
309        assert_eq!(
310            vm.segments
311                .memory
312                .get_integer((1, 11).into())
313                .unwrap()
314                .as_ref(),
315            &felt_str!("340282366920938463394229121463989152931")
316        );
317    }
318
319    #[test]
320    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
321    fn run_unsigned_div_rem_divide_by_zero() {
322        let mut vm = vm_with_range_check!();
323        //Initialize fp
324        vm.run_context.fp = 10;
325        //Create hint_data
326        let ids_data =
327            non_continuous_ids_data![("a", -9), ("div", -6), ("quotient", -3), ("remainder", 0)];
328        //Insert ids into memory
329        vm.segments = segments![
330            //a
331            ((1, 1), 83434123481193248),
332            ((1, 2), 82349321849739284),
333            ((1, 3), 839243219401320423),
334            //div
335            ((1, 4), 0),
336            ((1, 5), 0),
337            ((1, 6), 0)
338        ];
339        //Execute the hint
340        assert_matches!(
341            run_hint!(vm, ids_data, hint_code::UINT384_UNSIGNED_DIV_REM),
342            Err(HintError::Math(MathError::DividedByZero))
343        );
344    }
345
346    #[test]
347    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
348    fn run_unsigned_div_rem_invalid_memory_insert() {
349        let mut vm = vm_with_range_check!();
350        //Initialize fp
351        vm.run_context.fp = 10;
352        //Create hint_data
353        let ids_data =
354            non_continuous_ids_data![("a", -9), ("div", -6), ("quotient", -3), ("remainder", 0)];
355        //Insert ids into memory
356        vm.segments = segments![
357            //a
358            ((1, 1), 83434123481193248),
359            ((1, 2), 82349321849739284),
360            ((1, 3), 839243219401320423),
361            //div
362            ((1, 4), 9283430921839492319493),
363            ((1, 5), 313248123482483248),
364            ((1, 6), 3790328402913840),
365            //quotient
366            ((1, 7), 2)
367        ];
368        //Execute the hint
369        assert_matches!(
370            run_hint!(vm, ids_data, hint_code::UINT384_UNSIGNED_DIV_REM),
371            Err(HintError::Memory(
372                MemoryError::InconsistentMemory(bx)
373            )) if *bx == (Relocatable::from((1, 7)),
374                    MaybeRelocatable::from(Felt252::from(2)),
375                    MaybeRelocatable::from(Felt252::from(221)))
376        );
377    }
378
379    #[test]
380    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
381    fn run_split_128_ok() {
382        let mut vm = vm_with_range_check!();
383        //Initialize fp
384        vm.run_context.fp = 3;
385        //Create hint_data
386        let ids_data = ids_data!["a", "low", "high"];
387        //Insert ids into memory
388        vm.segments = segments![((1, 0), 34895349583295832495320945304)];
389        //Execute the hint
390        assert_matches!(
391            run_hint!(vm, ids_data, hint_code::UINT384_SPLIT_128),
392            Ok(())
393        );
394        //Check hint memory inserts
395        check_memory![
396            vm.segments.memory,
397            // low
398            ((1, 1), 34895349583295832495320945304),
399            // high
400            ((1, 2), 0)
401        ];
402    }
403
404    #[test]
405    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
406    fn run_split_128_ok_big_number() {
407        let mut vm = vm_with_range_check!();
408        //Initialize fp
409        vm.run_context.fp = 3;
410        //Create hint_data
411        let ids_data = ids_data!["a", "low", "high"];
412        //Insert ids into memory
413        vm.segments.add();
414        vm.segments.add();
415        vm.segments
416            .memory
417            .insert(
418                (1, 0).into(),
419                Felt252::from(u128::MAX) * Felt252::from(20_u32),
420            )
421            .unwrap();
422        //Execute the hint
423        assert_matches!(
424            run_hint!(vm, ids_data, hint_code::UINT384_SPLIT_128),
425            Ok(())
426        );
427        //Check hint memory inserts
428        check_memory![
429            vm.segments.memory,
430            // low
431            //((1, 1), 340282366920938463463374607431768211454)
432            // high
433            ((1, 2), 19)
434        ];
435        assert_eq!(
436            vm.segments
437                .memory
438                .get_integer((1, 1).into())
439                .unwrap()
440                .as_ref(),
441            &felt_str!("340282366920938463463374607431768211436")
442        );
443    }
444
445    #[test]
446    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
447    fn run_split_128_invalid_memory_insert() {
448        let mut vm = vm_with_range_check!();
449        //Initialize fp
450        vm.run_context.fp = 3;
451        //Create hint_data
452        let ids_data = ids_data!["a", "low", "high"];
453        //Insert ids into memory
454        vm.segments = segments![((1, 0), 34895349583295832495320945304), ((1, 1), 2)];
455        //Execute the hint
456        assert_matches!(
457            run_hint!(vm, ids_data, hint_code::UINT384_SPLIT_128),
458            Err(HintError::Memory(
459                MemoryError::InconsistentMemory(bx)
460            )) if *bx == (Relocatable::from((1, 1)),
461                    MaybeRelocatable::from(Felt252::from(2)),
462                    MaybeRelocatable::from(Felt252::from(34895349583295832495320945304_i128)))
463        );
464    }
465
466    #[test]
467    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
468    fn run_add_no_check_ok() {
469        let mut vm = vm_with_range_check!();
470        //Initialize fp
471        vm.run_context.fp = 10;
472        //Create hint_data
473        let ids_data = non_continuous_ids_data![
474            ("a", -10),
475            ("b", -7),
476            ("carry_d0", -4),
477            ("carry_d1", -3),
478            ("carry_d2", -2)
479        ];
480        //Insert ids into memory
481        vm.segments = segments![
482            // a
483            ((1, 0), 3789423292314891293),
484            ((1, 1), 21894),
485            ((1, 2), 340282366920938463463374607431768211455_u128),
486            // b
487            ((1, 3), 32838232),
488            ((1, 4), 17),
489            ((1, 5), 8)
490        ];
491        //Execute the hint
492        assert_matches!(
493            run_hint!(
494                vm,
495                ids_data,
496                hint_code::ADD_NO_UINT384_CHECK,
497                &mut exec_scopes_ref!(),
498                &[("path.path.path.SHIFT", crate::math_utils::pow2_const(128))]
499                    .into_iter()
500                    .map(|(k, v)| (k.to_string(), v))
501                    .collect()
502            ),
503            Ok(())
504        );
505        //Check hint memory inserts
506        check_memory![
507            vm.segments.memory,
508            // carry_d0
509            ((1, 6), 0),
510            // carry_d1
511            ((1, 7), 0),
512            // carry_d2
513            ((1, 8), 1)
514        ];
515    }
516
517    #[test]
518    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
519    fn run_add_no_check_missing_constant() {
520        let mut vm = vm_with_range_check!();
521        //Initialize fp
522        vm.run_context.fp = 10;
523        //Create hint_data
524        let ids_data = non_continuous_ids_data![
525            ("a", -10),
526            ("b", -7),
527            ("carry_d0", -3),
528            ("carry_d1", -2),
529            ("carry_d2", -1)
530        ];
531        //Insert ids into memory
532        vm.segments = segments![
533            // a
534            ((1, 0), 3789423292314891293),
535            ((1, 1), 21894),
536            ((1, 2), 340282366920938463463374607431768211455_u128),
537            // b
538            ((1, 3), 32838232),
539            ((1, 4), 17),
540            ((1, 5), 8)
541        ];
542        //Execute the hint
543        assert_matches!(
544            run_hint!(vm, ids_data, hint_code::ADD_NO_UINT384_CHECK),
545            Err(HintError::MissingConstant(bx)) if *bx == "SHIFT"
546        );
547    }
548
549    #[test]
550    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
551    fn run_sqrt_ok() {
552        let mut vm = vm_with_range_check!();
553        //Initialize fp
554        vm.run_context.fp = 5;
555        //Create hint_data
556        let ids_data = non_continuous_ids_data![("a", -5), ("root", -2)];
557        //Insert ids into memory
558        vm.segments = segments![
559            //a
560            ((1, 0), 83434123481193248),
561            ((1, 1), 82349321849739284),
562            ((1, 2), 839243219401320423)
563        ];
564        //Execute the hint
565        assert_matches!(run_hint!(vm, ids_data, hint_code::UINT384_SQRT), Ok(()));
566        //Check hint memory inserts
567        check_memory![
568            vm.segments.memory,
569            // root
570            ((1, 3), 100835122758113432298839930225328621183),
571            ((1, 4), 916102188),
572            ((1, 5), 0)
573        ];
574    }
575
576    #[test]
577    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
578    fn run_sqrt_assertion_fail() {
579        let mut vm = vm_with_range_check!();
580        //Initialize fp
581        vm.run_context.fp = 5;
582        //Create hint_data
583        let ids_data = non_continuous_ids_data![("a", -5), ("root", -2)];
584        //Insert ids into memory
585        //Insert ids into memory
586        vm.segments = segments![
587            //a
588            ((1, 0), (-1)),
589            ((1, 1), (-1)),
590            ((1, 2), (-1))
591        ];
592        //Execute the hint
593        assert_matches!(
594            run_hint!(vm, ids_data, hint_code::UINT384_SQRT),
595            Err(HintError::AssertionFailed(bx)) if bx.as_ref() == "assert 0 <= root < 2 ** 192"
596        );
597    }
598
599    #[test]
600    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
601    fn run_signed_nn_ok_positive() {
602        let mut vm = vm_with_range_check!();
603        //Initialize fp
604        vm.run_context.fp = 3;
605        //Create hint_data
606        let ids_data = non_continuous_ids_data![("a", -2)];
607        //Insert ids into memory
608        vm.segments = segments![
609            //a.d2
610            ((1, 3), 1)
611        ];
612        //Execute the hint
613        assert!(run_hint!(vm, ids_data, hint_code::UINT384_SIGNED_NN).is_ok());
614        //Check hint memory inserts
615        check_memory![
616            vm.segments.memory,
617            // ap
618            ((1, 0), 1)
619        ];
620    }
621
622    #[test]
623    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
624    fn run_signed_nn_missing_identifier() {
625        let mut vm = vm_with_range_check!();
626        //Initialize fp
627        vm.run_context.fp = 3;
628        //Create hint_data
629        let ids_data = non_continuous_ids_data![("a", -2)];
630        //Insert ids into memory
631        vm.segments = segments![
632            //a.d0
633            ((1, 1), 1),
634            //a.d1
635            ((1, 2), 1) //a.d2
636        ];
637        //Execute the hint
638        assert_matches!(run_hint!(vm, ids_data, hint_code::UINT384_SIGNED_NN),
639            Err(HintError::IdentifierHasNoMember(bx)) if *bx == ("a".to_string(), "d2".to_string())
640        );
641    }
642
643    #[test]
644    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
645    fn run_signed_nn_ok_negative() {
646        let mut vm = vm_with_range_check!();
647        //Initialize fp
648        vm.run_context.fp = 3;
649        //Create hint_data
650        let ids_data = non_continuous_ids_data![("a", -2)];
651        //Insert ids into memory
652        vm.segments = segments![
653            //a.d0
654            ((1, 3), 170141183460469231731687303715884105729_u128)
655        ];
656        //Execute the hint
657        assert!(run_hint!(vm, ids_data, hint_code::UINT384_SIGNED_NN).is_ok());
658        //Check hint memory inserts
659        check_memory![
660            vm.segments.memory,
661            // ap
662            ((1, 0), 0)
663        ];
664    }
665
666    #[test]
667    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
668    fn run_uint384_sub_a_b_ok_a_max() {
669        let mut vm = vm_with_range_check!();
670        //Initialize fp
671        vm.run_context.fp = 10;
672        //Create hint_data
673        let ids_data = non_continuous_ids_data![("a", -10), ("b", -7), ("p", -4), ("res", -1)];
674        //Insert ids into memory
675        vm.segments = segments![
676            // a
677            ((1, 0), 6),
678            ((1, 1), 6),
679            ((1, 2), 6),
680            // b
681            ((1, 3), 1),
682            ((1, 4), 1),
683            ((1, 5), 1),
684            // p
685            ((1, 6), 7),
686            ((1, 7), 7),
687            ((1, 8), 7)
688        ];
689        //Execute the hint
690        assert!(run_hint!(vm, ids_data, hint_code::SUB_REDUCED_A_AND_REDUCED_B).is_ok());
691        //Check hint memory inserts
692        check_memory![
693            vm.segments.memory,
694            // res
695            ((1, 9), 5),
696            ((1, 10), 5),
697            ((1, 11), 5)
698        ];
699    }
700
701    #[test]
702    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
703    fn run_uint384_sub_a_b_ok_b_max() {
704        let mut vm = vm_with_range_check!();
705        //Initialize fp
706        vm.run_context.fp = 10;
707        //Create hint_data
708        let ids_data = non_continuous_ids_data![("a", -10), ("b", -7), ("p", -4), ("res", -1)];
709        //Insert ids into memory
710        vm.segments = segments![
711            // a
712            ((1, 0), 3),
713            ((1, 1), 3),
714            ((1, 2), 3),
715            // b
716            ((1, 3), 5),
717            ((1, 4), 5),
718            ((1, 5), 5),
719            // p
720            ((1, 6), 7),
721            ((1, 7), 7),
722            ((1, 8), 7)
723        ];
724        //Execute the hint
725        assert!(run_hint!(vm, ids_data, hint_code::SUB_REDUCED_A_AND_REDUCED_B).is_ok());
726        //Check hint memory inserts
727        check_memory![
728            vm.segments.memory,
729            // res
730            ((1, 9), 5),
731            ((1, 10), 5),
732            ((1, 11), 5)
733        ];
734    }
735}