1use super::secp::bigint_utils::{Uint384, Uint768};
2use crate::stdlib::{collections::HashMap, prelude::*};
3use crate::types::errors::math_errors::MathError;
4use crate::{
5 hint_processor::hint_processor_definition::HintReference,
6 serde::deserialize_program::ApTracking,
7 vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
8};
9use num_integer::Integer;
10use num_traits::Zero;
11
12pub fn unsigned_div_rem_uint768_by_uint384(
50 vm: &mut VirtualMachine,
51 ids_data: &HashMap<String, HintReference>,
52 ap_tracking: &ApTracking,
53) -> Result<(), HintError> {
54 let a = Uint768::from_var_name("a", vm, ids_data, ap_tracking)?.pack();
55 let div = Uint384::from_var_name("div", vm, ids_data, ap_tracking)?.pack();
56
57 if div.is_zero() {
58 return Err(MathError::DividedByZero.into());
59 }
60 let (quotient, remainder) = a.div_mod_floor(&div);
61 let quotient_split = Uint768::split("ient);
62 quotient_split.insert_from_var_name("quotient", vm, ids_data, ap_tracking)?;
63 let remainder_split = Uint384::split(&remainder);
64 remainder_split.insert_from_var_name("remainder", vm, ids_data, ap_tracking)
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::any_box;
71 use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
72 use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData;
73 use crate::hint_processor::builtin_hint_processor::hint_code;
74 use crate::hint_processor::builtin_hint_processor::secp::bigint_utils::Uint768;
75 use crate::hint_processor::hint_processor_definition::HintProcessorLogic;
76 use crate::utils::test_utils::*;
77
78 use assert_matches::assert_matches;
79
80 use crate::felt_str;
81 use crate::Felt252;
82 use rstest::rstest;
83 #[cfg(target_arch = "wasm32")]
84 use wasm_bindgen_test::*;
85
86 #[test]
87 fn get_uint768_from_base_addr_ok() {
88 let mut vm = vm!();
90 vm.segments = segments![
91 ((1, 0), 1),
92 ((1, 1), 2),
93 ((1, 2), 3),
94 ((1, 3), 4),
95 ((1, 4), 5),
96 ((1, 5), 6)
97 ];
98 let x = Uint768::from_base_addr((1, 0).into(), "x", &vm).unwrap();
99 assert_eq!(x.limbs[0].as_ref(), &Felt252::ONE);
100 assert_eq!(x.limbs[1].as_ref(), &Felt252::from(2));
101 assert_eq!(x.limbs[2].as_ref(), &Felt252::from(3));
102 }
103
104 fn assert_is_err_identifier_has_no_member(
105 result: Result<Uint768, HintError>,
106 x: &str,
107 y: &str,
108 ) {
109 assert_matches!(result, Err(HintError::IdentifierHasNoMember(bx)) if *bx == (x.to_string(), y.to_string()))
110 }
111
112 #[test]
113 fn get_uint768_from_base_addr_missing_member_d0() {
114 let mut vm = vm!();
116 vm.segments = segments![((0, 1), 2)];
117 let r = Uint768::from_base_addr((0, 0).into(), "x", &vm);
118 assert_is_err_identifier_has_no_member(r, "x", "d0")
119 }
120
121 #[test]
122 fn get_uint768_from_base_addr_missing_member_d1() {
123 let mut vm = vm!();
125 vm.segments = segments![((0, 0), 1)];
126 let r = Uint768::from_base_addr((0, 0).into(), "x", &vm);
127 assert_is_err_identifier_has_no_member(r, "x", "d1")
128 }
129
130 #[test]
131 fn get_uint768_from_base_addr_missing_member_d2() {
132 let mut vm = vm!();
134 vm.segments = segments![((0, 0), 1), ((0, 1), 2)];
135 let r = Uint768::from_base_addr((0, 0).into(), "x", &vm);
136 assert_is_err_identifier_has_no_member(r, "x", "d2")
137 }
138
139 #[test]
140 fn get_uint768_from_base_addr_missing_member_d3() {
141 let mut vm = vm!();
143 vm.segments = segments![((0, 0), 1), ((0, 1), 2), ((0, 2), 3)];
144 let r = Uint768::from_base_addr((0, 0).into(), "x", &vm);
145 assert_is_err_identifier_has_no_member(r, "x", "d3")
146 }
147
148 #[test]
149 fn get_uint768_from_base_addr_missing_member_d4() {
150 let mut vm = vm!();
152 vm.segments = segments![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)];
153 let r = Uint768::from_base_addr((0, 0).into(), "x", &vm);
154 assert_is_err_identifier_has_no_member(r, "x", "d4")
155 }
156
157 #[test]
158 fn get_uint768_from_base_addr_missing_member_d5() {
159 let mut vm = vm!();
161 vm.segments = segments![
162 ((0, 0), 1),
163 ((0, 1), 2),
164 ((0, 2), 3),
165 ((0, 3), 4),
166 ((0, 4), 5)
167 ];
168 let r = Uint768::from_base_addr((0, 0).into(), "x", &vm);
169 assert_is_err_identifier_has_no_member(r, "x", "d5")
170 }
171
172 #[test]
173 fn get_uint768_from_var_name_ok() {
174 let mut vm = vm!();
176 vm.set_fp(1);
177 vm.segments = segments![
178 ((1, 0), 1),
179 ((1, 1), 2),
180 ((1, 2), 3),
181 ((1, 3), 4),
182 ((1, 4), 5),
183 ((1, 5), 6)
184 ];
185 let ids_data = ids_data!["x"];
186 let x = Uint768::from_var_name("x", &vm, &ids_data, &ApTracking::default()).unwrap();
187 assert_eq!(x.limbs[0].as_ref(), &Felt252::ONE);
188 assert_eq!(x.limbs[1].as_ref(), &Felt252::from(2));
189 assert_eq!(x.limbs[2].as_ref(), &Felt252::from(3));
190 }
191
192 #[test]
193 fn get_uint768_from_var_name_missing_member() {
194 let mut vm = vm!();
196 vm.set_fp(1);
197 vm.segments = segments![((1, 0), 1), ((1, 1), 2)];
198 let ids_data = ids_data!["x"];
199 let r = Uint768::from_var_name("x", &vm, &ids_data, &ApTracking::default());
200 assert_is_err_identifier_has_no_member(r, "x", "d2")
201 }
202
203 #[test]
204 fn get_uint768_from_var_name_invalid_reference() {
205 let mut vm = vm!();
206 vm.segments = segments![((1, 0), 1), ((1, 1), 2), ((1, 2), 3)];
207 let ids_data = ids_data!["x"];
208 let r = Uint768::from_var_name("x", &vm, &ids_data, &ApTracking::default());
209 assert_matches!(r, Err(HintError::UnknownIdentifier(bx)) if bx.as_ref() == "x")
210 }
211
212 #[rstest]
213 #[case(hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384)]
214 #[case(hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED)]
215 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
216 fn run_unsigned_div_rem_ok(#[case] hint_code: &str) {
217 let mut vm = vm_with_range_check!();
218 vm.run_context.fp = 17;
220 let ids_data = non_continuous_ids_data![
222 ("a", -17),
223 ("div", -11),
224 ("quotient", -8),
225 ("remainder", -2)
226 ];
227 vm.segments = segments![
229 ((1, 0), 1),
231 ((1, 1), 2),
232 ((1, 2), 3),
233 ((1, 3), 4),
234 ((1, 4), 5),
235 ((1, 5), 6),
236 ((1, 6), 6),
238 ((1, 7), 7),
239 ((1, 8), 8)
240 ];
241 assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
243 check_memory![
245 vm.segments.memory,
246 ((1, 12), 0),
251 ((1, 13), 0),
252 ((1, 14), 0),
253 ((1, 15), 71778311772385457136805581255138607105),
255 ((1, 16), 147544307532125661892322583691118247938),
256 ((1, 17), 3)
257 ];
258 assert_eq!(
259 vm.segments
260 .memory
261 .get_integer((1, 9).into())
262 .unwrap()
263 .as_ref(),
264 &felt_str!("328319314958874220607240343889245110272")
265 );
266 assert_eq!(
267 vm.segments
268 .memory
269 .get_integer((1, 10).into())
270 .unwrap()
271 .as_ref(),
272 &felt_str!("329648542954659136480144150949525454847")
273 );
274 assert_eq!(
275 vm.segments
276 .memory
277 .get_integer((1, 11).into())
278 .unwrap()
279 .as_ref(),
280 &felt_str!("255211775190703847597530955573826158591")
281 );
282 }
283
284 #[rstest]
285 #[case(hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384)]
286 #[case(hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED)]
287 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
288 fn run_unsigned_div_rem_divide_by_zero(#[case] hint_code: &str) {
289 let mut vm = vm_with_range_check!();
290 vm.run_context.fp = 17;
292 let ids_data = non_continuous_ids_data![
294 ("a", -17),
295 ("div", -11),
296 ("quotient", -8),
297 ("remainder", -2)
298 ];
299 vm.segments = segments![
301 ((1, 0), 1),
303 ((1, 1), 2),
304 ((1, 2), 3),
305 ((1, 3), 4),
306 ((1, 4), 5),
307 ((1, 5), 6),
308 ((1, 6), 0),
310 ((1, 7), 0),
311 ((1, 8), 0)
312 ];
313 assert_matches!(
315 run_hint!(vm, ids_data, hint_code),
316 Err(HintError::Math(MathError::DividedByZero))
317 );
318 }
319}