cairo_vm/hint_processor/builtin_hint_processor/
ec_recover.rs

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
15/* Implements Hint:
16%{
17    from starkware.cairo.common.cairo_secp.secp_utils import pack
18    from starkware.python.math_utils import div_mod, safe_div
19
20    N = pack(ids.n, PRIME)
21    x = pack(ids.x, PRIME) % N
22    s = pack(ids.s, PRIME) % N,
23    value = res = div_mod(x, s, N)
24%}
25 */
26pub 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
49/* Implements Hint:
50%{
51    from starkware.cairo.common.cairo_secp.secp_utils import pack
52    from starkware.python.math_utils import div_mod, safe_div
53
54    a = pack(ids.x, PRIME)
55    b = pack(ids.s, PRIME)
56    value = res = a - b
57%}
58 */
59pub 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
74/* Implements Hint:
75%{
76    from starkware.cairo.common.cairo_secp.secp_utils import pack
77    from starkware.python.math_utils import div_mod, safe_div
78
79    a = pack(ids.a, PRIME)
80    b = pack(ids.b, PRIME)
81    product = a * b
82    m = pack(ids.m, PRIME)
83
84    value = res = product % m
85%}
86 */
87pub 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
109/* Implements Hint:
110%{
111    value = k = product // m
112%}
113 */
114pub 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            //n
160            ((1, 0), 177),
161            ((1, 1), 0),
162            ((1, 2), 0),
163            //x
164            ((1, 3), 25),
165            ((1, 4), 0),
166            ((1, 5), 0),
167            //s
168            ((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            //n
198            ((1, 0), 0),
199            ((1, 1), 0),
200            ((1, 2), 0),
201            //x
202            ((1, 3), 25),
203            ((1, 4), 0),
204            ((1, 5), 0),
205            //s
206            ((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            //a
233            ((1, 0), 100),
234            ((1, 1), 0),
235            ((1, 2), 0),
236            //b
237            ((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            //a
267            ((1, 0), 60),
268            ((1, 1), 0),
269            ((1, 2), 0),
270            //b
271            ((1, 3), 2),
272            ((1, 4), 0),
273            ((1, 5), 0),
274            //m
275            ((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            //a
310            ((1, 0), 60),
311            ((1, 1), 0),
312            ((1, 2), 0),
313            //b
314            ((1, 3), 2),
315            ((1, 4), 0),
316            ((1, 5), 0),
317            //m
318            ((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}