Skip to main content

cairo_vm/hint_processor/builtin_hint_processor/
ec_recover.rs

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
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    #[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            //n
156            ((1, 0), 177),
157            ((1, 1), 0),
158            ((1, 2), 0),
159            //x
160            ((1, 3), 25),
161            ((1, 4), 0),
162            ((1, 5), 0),
163            //s
164            ((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            //n
193            ((1, 0), 0),
194            ((1, 1), 0),
195            ((1, 2), 0),
196            //x
197            ((1, 3), 25),
198            ((1, 4), 0),
199            ((1, 5), 0),
200            //s
201            ((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            //a
227            ((1, 0), 100),
228            ((1, 1), 0),
229            ((1, 2), 0),
230            //b
231            ((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            //a
260            ((1, 0), 60),
261            ((1, 1), 0),
262            ((1, 2), 0),
263            //b
264            ((1, 3), 2),
265            ((1, 4), 0),
266            ((1, 5), 0),
267            //m
268            ((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            //a
302            ((1, 0), 60),
303            ((1, 1), 0),
304            ((1, 2), 0),
305            //b
306            ((1, 3), 2),
307            ((1, 4), 0),
308            ((1, 5), 0),
309            //m
310            ((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}