1use num_integer::Integer;
2
3use super::secp::bigint_utils::BigInt3;
4use crate::{
5 hint_processor::hint_processor_definition::HintReference,
6 math_utils::div_mod,
7 serde::deserialize_program::ApTracking,
8 types::{errors::math_errors::MathError, exec_scope::ExecutionScopes},
9 vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
10};
11use num_bigint::BigInt;
12use num_traits::Zero;
13use std::collections::HashMap;
14
15pub fn ec_recover_divmod_n_packed(
27 vm: &mut VirtualMachine,
28 exec_scopes: &mut ExecutionScopes,
29 ids_data: &HashMap<String, HintReference>,
30 ap_tracking: &ApTracking,
31) -> Result<(), HintError> {
32 let n = BigInt3::from_var_name("n", vm, ids_data, ap_tracking)?.pack86();
33 if n.is_zero() {
34 return Err(MathError::DividedByZero.into());
35 }
36 let x = BigInt3::from_var_name("x", vm, ids_data, ap_tracking)?
37 .pack86()
38 .mod_floor(&n);
39 let s = BigInt3::from_var_name("s", vm, ids_data, ap_tracking)?
40 .pack86()
41 .mod_floor(&n);
42
43 let value = div_mod(&x, &s, &n)?;
44 exec_scopes.insert_value("value", value.clone());
45 exec_scopes.insert_value("res", value);
46 Ok(())
47}
48
49pub fn ec_recover_sub_a_b(
60 vm: &mut VirtualMachine,
61 exec_scopes: &mut ExecutionScopes,
62 ids_data: &HashMap<String, HintReference>,
63 ap_tracking: &ApTracking,
64) -> Result<(), HintError> {
65 let a = BigInt3::from_var_name("a", vm, ids_data, ap_tracking)?.pack86();
66 let b = BigInt3::from_var_name("b", vm, ids_data, ap_tracking)?.pack86();
67
68 let value = a - b;
69 exec_scopes.insert_value("value", value.clone());
70 exec_scopes.insert_value("res", value);
71 Ok(())
72}
73
74pub fn ec_recover_product_mod(
88 vm: &mut VirtualMachine,
89 exec_scopes: &mut ExecutionScopes,
90 ids_data: &HashMap<String, HintReference>,
91 ap_tracking: &ApTracking,
92) -> Result<(), HintError> {
93 let a = BigInt3::from_var_name("a", vm, ids_data, ap_tracking)?.pack86();
94 let b = BigInt3::from_var_name("b", vm, ids_data, ap_tracking)?.pack86();
95 let m = BigInt3::from_var_name("m", vm, ids_data, ap_tracking)?.pack86();
96 if m.is_zero() {
97 return Err(MathError::DividedByZero.into());
98 }
99
100 let product = a * b;
101 let value = product.mod_floor(&m);
102 exec_scopes.insert_value("product", product);
103 exec_scopes.insert_value("m", m);
104 exec_scopes.insert_value("value", value.clone());
105 exec_scopes.insert_value("res", value);
106 Ok(())
107}
108
109pub fn ec_recover_product_div_m(exec_scopes: &mut ExecutionScopes) -> Result<(), HintError> {
115 let product: &BigInt = exec_scopes.get_ref("product")?;
116 let m: &BigInt = exec_scopes.get_ref("m")?;
117 if m.is_zero() {
118 return Err(MathError::DividedByZero.into());
119 }
120 let value = product.div_floor(m);
121 exec_scopes.insert_value("k", value.clone());
122 exec_scopes.insert_value("value", value);
123 Ok(())
124}
125
126#[cfg(test)]
127mod tests {
128 use num_bigint::BigInt;
129
130 use super::*;
131 use crate::hint_processor::builtin_hint_processor::hint_code;
132 use crate::hint_processor::hint_processor_definition::HintReference;
133 use crate::utils::test_utils::*;
134 use crate::{
135 any_box,
136 hint_processor::{
137 builtin_hint_processor::builtin_hint_processor_definition::{
138 BuiltinHintProcessor, HintProcessorData,
139 },
140 hint_processor_definition::HintProcessorLogic,
141 },
142 types::exec_scope::ExecutionScopes,
143 };
144 use assert_matches::assert_matches;
145
146 #[test]
147 fn run_ec_recover_divmod_n_packed_ok() {
148 let mut vm = vm!();
149 let mut exec_scopes = ExecutionScopes::new();
150
151 vm.run_context.fp = 8;
152 let ids_data = non_continuous_ids_data![("n", -8), ("x", -5), ("s", -2)];
153
154 vm.segments = segments![
155 ((1, 0), 177),
157 ((1, 1), 0),
158 ((1, 2), 0),
159 ((1, 3), 25),
161 ((1, 4), 0),
162 ((1, 5), 0),
163 ((1, 6), 5),
165 ((1, 7), 0),
166 ((1, 8), 0)
167 ];
168
169 assert!(run_hint!(
170 vm,
171 ids_data,
172 hint_code::EC_RECOVER_DIV_MOD_N_PACKED,
173 &mut exec_scopes
174 )
175 .is_ok());
176
177 check_scope!(
178 &exec_scopes,
179 [("value", BigInt::from(5)), ("res", BigInt::from(5))]
180 );
181 }
182
183 #[test]
184 fn run_ec_recover_divmod_n_is_zero() {
185 let mut vm = vm!();
186 let mut exec_scopes = ExecutionScopes::new();
187
188 vm.run_context.fp = 8;
189 let ids_data = non_continuous_ids_data![("n", -8), ("x", -5), ("s", -2)];
190
191 vm.segments = segments![
192 ((1, 0), 0),
194 ((1, 1), 0),
195 ((1, 2), 0),
196 ((1, 3), 25),
198 ((1, 4), 0),
199 ((1, 5), 0),
200 ((1, 6), 5),
202 ((1, 7), 0),
203 ((1, 8), 0)
204 ];
205
206 assert_matches!(
207 run_hint!(
208 vm,
209 ids_data,
210 hint_code::EC_RECOVER_DIV_MOD_N_PACKED,
211 &mut exec_scopes
212 ),
213 Err(HintError::Math(MathError::DividedByZero))
214 );
215 }
216
217 #[test]
218 fn run_ec_recover_sub_a_b_ok() {
219 let mut vm = vm!();
220 let mut exec_scopes = ExecutionScopes::new();
221
222 vm.run_context.fp = 8;
223 let ids_data = non_continuous_ids_data![("a", -8), ("b", -5)];
224
225 vm.segments = segments![
226 ((1, 0), 100),
228 ((1, 1), 0),
229 ((1, 2), 0),
230 ((1, 3), 25),
232 ((1, 4), 0),
233 ((1, 5), 0),
234 ];
235
236 assert!(run_hint!(
237 vm,
238 ids_data,
239 hint_code::EC_RECOVER_SUB_A_B,
240 &mut exec_scopes
241 )
242 .is_ok());
243
244 check_scope!(
245 &exec_scopes,
246 [("value", BigInt::from(75)), ("res", BigInt::from(75))]
247 );
248 }
249
250 #[test]
251 fn run_ec_recover_product_mod_ok() {
252 let mut vm = vm!();
253 let mut exec_scopes = ExecutionScopes::new();
254
255 vm.run_context.fp = 8;
256 let ids_data = non_continuous_ids_data![("a", -8), ("b", -5), ("m", -2)];
257
258 vm.segments = segments![
259 ((1, 0), 60),
261 ((1, 1), 0),
262 ((1, 2), 0),
263 ((1, 3), 2),
265 ((1, 4), 0),
266 ((1, 5), 0),
267 ((1, 6), 100),
269 ((1, 7), 0),
270 ((1, 8), 0)
271 ];
272
273 assert!(run_hint!(
274 vm,
275 ids_data,
276 hint_code::EC_RECOVER_PRODUCT_MOD,
277 &mut exec_scopes
278 )
279 .is_ok());
280
281 check_scope!(
282 &exec_scopes,
283 [
284 ("value", BigInt::from(20)),
285 ("res", BigInt::from(20)),
286 ("product", BigInt::from(120)),
287 ("m", BigInt::from(100))
288 ]
289 );
290 }
291
292 #[test]
293 fn run_ec_recover_product_mod_m_zero() {
294 let mut vm = vm!();
295 let mut exec_scopes = ExecutionScopes::new();
296
297 vm.run_context.fp = 8;
298 let ids_data = non_continuous_ids_data![("a", -8), ("b", -5), ("m", -2)];
299
300 vm.segments = segments![
301 ((1, 0), 60),
303 ((1, 1), 0),
304 ((1, 2), 0),
305 ((1, 3), 2),
307 ((1, 4), 0),
308 ((1, 5), 0),
309 ((1, 6), 0),
311 ((1, 7), 0),
312 ((1, 8), 0)
313 ];
314
315 assert_matches!(
316 run_hint!(
317 vm,
318 ids_data,
319 hint_code::EC_RECOVER_PRODUCT_MOD,
320 &mut exec_scopes
321 ),
322 Err(HintError::Math(MathError::DividedByZero))
323 );
324 }
325
326 #[test]
327 fn run_ec_recover_product_div_m_ok() {
328 let mut vm = vm!();
329 let mut exec_scopes = ExecutionScopes::new();
330 exec_scopes.insert_value("product", BigInt::from(250));
331 exec_scopes.insert_value("m", BigInt::from(100));
332
333 let ids_data = ids_data!["none"];
334
335 assert!(run_hint!(
336 vm,
337 ids_data,
338 hint_code::EC_RECOVER_PRODUCT_DIV_M,
339 &mut exec_scopes
340 )
341 .is_ok());
342
343 check_scope!(
344 &exec_scopes,
345 [("value", BigInt::from(2)), ("k", BigInt::from(2))]
346 );
347 }
348
349 #[test]
350 fn run_ec_recover_product_div_m_zero() {
351 let mut vm = vm!();
352 let mut exec_scopes = ExecutionScopes::new();
353 exec_scopes.insert_value("product", BigInt::from(250));
354 exec_scopes.insert_value("m", BigInt::from(0));
355
356 let ids_data = ids_data!["none"];
357
358 assert_matches!(
359 run_hint!(
360 vm,
361 ids_data,
362 hint_code::EC_RECOVER_PRODUCT_DIV_M,
363 &mut exec_scopes
364 ),
365 Err(HintError::Math(MathError::DividedByZero))
366 );
367 }
368}