1use num_integer::Integer;
2
3use super::secp::bigint_utils::BigInt3;
4use crate::stdlib::{collections::HashMap, prelude::*};
5use crate::{
6 hint_processor::hint_processor_definition::HintReference,
7 math_utils::div_mod,
8 serde::deserialize_program::ApTracking,
9 types::{errors::math_errors::MathError, exec_scope::ExecutionScopes},
10 vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
11};
12use num_bigint::BigInt;
13use num_traits::Zero;
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 #[cfg(target_arch = "wasm32")]
147 use wasm_bindgen_test::*;
148
149 #[test]
150 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
151 fn run_ec_recover_divmod_n_packed_ok() {
152 let mut vm = vm!();
153 let mut exec_scopes = ExecutionScopes::new();
154
155 vm.run_context.fp = 8;
156 let ids_data = non_continuous_ids_data![("n", -8), ("x", -5), ("s", -2)];
157
158 vm.segments = segments![
159 ((1, 0), 177),
161 ((1, 1), 0),
162 ((1, 2), 0),
163 ((1, 3), 25),
165 ((1, 4), 0),
166 ((1, 5), 0),
167 ((1, 6), 5),
169 ((1, 7), 0),
170 ((1, 8), 0)
171 ];
172
173 assert!(run_hint!(
174 vm,
175 ids_data,
176 hint_code::EC_RECOVER_DIV_MOD_N_PACKED,
177 &mut exec_scopes
178 )
179 .is_ok());
180
181 check_scope!(
182 &exec_scopes,
183 [("value", BigInt::from(5)), ("res", BigInt::from(5))]
184 );
185 }
186
187 #[test]
188 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
189 fn run_ec_recover_divmod_n_is_zero() {
190 let mut vm = vm!();
191 let mut exec_scopes = ExecutionScopes::new();
192
193 vm.run_context.fp = 8;
194 let ids_data = non_continuous_ids_data![("n", -8), ("x", -5), ("s", -2)];
195
196 vm.segments = segments![
197 ((1, 0), 0),
199 ((1, 1), 0),
200 ((1, 2), 0),
201 ((1, 3), 25),
203 ((1, 4), 0),
204 ((1, 5), 0),
205 ((1, 6), 5),
207 ((1, 7), 0),
208 ((1, 8), 0)
209 ];
210
211 assert_matches!(
212 run_hint!(
213 vm,
214 ids_data,
215 hint_code::EC_RECOVER_DIV_MOD_N_PACKED,
216 &mut exec_scopes
217 ),
218 Err(HintError::Math(MathError::DividedByZero))
219 );
220 }
221
222 #[test]
223 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
224 fn run_ec_recover_sub_a_b_ok() {
225 let mut vm = vm!();
226 let mut exec_scopes = ExecutionScopes::new();
227
228 vm.run_context.fp = 8;
229 let ids_data = non_continuous_ids_data![("a", -8), ("b", -5)];
230
231 vm.segments = segments![
232 ((1, 0), 100),
234 ((1, 1), 0),
235 ((1, 2), 0),
236 ((1, 3), 25),
238 ((1, 4), 0),
239 ((1, 5), 0),
240 ];
241
242 assert!(run_hint!(
243 vm,
244 ids_data,
245 hint_code::EC_RECOVER_SUB_A_B,
246 &mut exec_scopes
247 )
248 .is_ok());
249
250 check_scope!(
251 &exec_scopes,
252 [("value", BigInt::from(75)), ("res", BigInt::from(75))]
253 );
254 }
255
256 #[test]
257 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
258 fn run_ec_recover_product_mod_ok() {
259 let mut vm = vm!();
260 let mut exec_scopes = ExecutionScopes::new();
261
262 vm.run_context.fp = 8;
263 let ids_data = non_continuous_ids_data![("a", -8), ("b", -5), ("m", -2)];
264
265 vm.segments = segments![
266 ((1, 0), 60),
268 ((1, 1), 0),
269 ((1, 2), 0),
270 ((1, 3), 2),
272 ((1, 4), 0),
273 ((1, 5), 0),
274 ((1, 6), 100),
276 ((1, 7), 0),
277 ((1, 8), 0)
278 ];
279
280 assert!(run_hint!(
281 vm,
282 ids_data,
283 hint_code::EC_RECOVER_PRODUCT_MOD,
284 &mut exec_scopes
285 )
286 .is_ok());
287
288 check_scope!(
289 &exec_scopes,
290 [
291 ("value", BigInt::from(20)),
292 ("res", BigInt::from(20)),
293 ("product", BigInt::from(120)),
294 ("m", BigInt::from(100))
295 ]
296 );
297 }
298
299 #[test]
300 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
301 fn run_ec_recover_product_mod_m_zero() {
302 let mut vm = vm!();
303 let mut exec_scopes = ExecutionScopes::new();
304
305 vm.run_context.fp = 8;
306 let ids_data = non_continuous_ids_data![("a", -8), ("b", -5), ("m", -2)];
307
308 vm.segments = segments![
309 ((1, 0), 60),
311 ((1, 1), 0),
312 ((1, 2), 0),
313 ((1, 3), 2),
315 ((1, 4), 0),
316 ((1, 5), 0),
317 ((1, 6), 0),
319 ((1, 7), 0),
320 ((1, 8), 0)
321 ];
322
323 assert_matches!(
324 run_hint!(
325 vm,
326 ids_data,
327 hint_code::EC_RECOVER_PRODUCT_MOD,
328 &mut exec_scopes
329 ),
330 Err(HintError::Math(MathError::DividedByZero))
331 );
332 }
333
334 #[test]
335 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
336 fn run_ec_recover_product_div_m_ok() {
337 let mut vm = vm!();
338 let mut exec_scopes = ExecutionScopes::new();
339 exec_scopes.insert_value("product", BigInt::from(250));
340 exec_scopes.insert_value("m", BigInt::from(100));
341
342 let ids_data = ids_data!["none"];
343
344 assert!(run_hint!(
345 vm,
346 ids_data,
347 hint_code::EC_RECOVER_PRODUCT_DIV_M,
348 &mut exec_scopes
349 )
350 .is_ok());
351
352 check_scope!(
353 &exec_scopes,
354 [("value", BigInt::from(2)), ("k", BigInt::from(2))]
355 );
356 }
357
358 #[test]
359 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
360 fn run_ec_recover_product_div_m_zero() {
361 let mut vm = vm!();
362 let mut exec_scopes = ExecutionScopes::new();
363 exec_scopes.insert_value("product", BigInt::from(250));
364 exec_scopes.insert_value("m", BigInt::from(0));
365
366 let ids_data = ids_data!["none"];
367
368 assert_matches!(
369 run_hint!(
370 vm,
371 ids_data,
372 hint_code::EC_RECOVER_PRODUCT_DIV_M,
373 &mut exec_scopes
374 ),
375 Err(HintError::Math(MathError::DividedByZero))
376 );
377 }
378}