1use crate::Felt252;
2use crate::{
3 any_box,
4 hint_processor::{
5 builtin_hint_processor::{hint_utils::get_integer_from_var_name, secp::secp_utils::BETA},
6 hint_processor_definition::HintReference,
7 },
8 math_utils::{div_mod, safe_div_bigint},
9 serde::deserialize_program::ApTracking,
10 stdlib::{collections::HashMap, ops::Shr, prelude::*},
11 types::exec_scope::ExecutionScopes,
12 vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
13};
14use core::ops::Add;
15use num_bigint::BigInt;
16use num_integer::Integer;
17
18use super::{
19 bigint_utils::Uint384,
20 secp_utils::{N, SECP_P},
21};
22
23pub fn div_mod_n_packed(
32 vm: &mut VirtualMachine,
33 exec_scopes: &mut ExecutionScopes,
34 ids_data: &HashMap<String, HintReference>,
35 ap_tracking: &ApTracking,
36 n: &BigInt,
37) -> Result<(), HintError> {
38 let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?.pack86();
39 let b = Uint384::from_var_name("b", vm, ids_data, ap_tracking)?.pack86();
40
41 let value = div_mod(&a, &b, n)?;
42 exec_scopes.insert_value("a", a);
43 exec_scopes.insert_value("b", b);
44 exec_scopes.insert_value("value", value.clone());
45 exec_scopes.insert_value("res", value);
46 Ok(())
47}
48
49pub fn div_mod_n_packed_divmod(
50 vm: &mut VirtualMachine,
51 exec_scopes: &mut ExecutionScopes,
52 ids_data: &HashMap<String, HintReference>,
53 ap_tracking: &ApTracking,
54) -> Result<(), HintError> {
55 exec_scopes.assign_or_update_variable("N", any_box!(N.clone()));
56 div_mod_n_packed(vm, exec_scopes, ids_data, ap_tracking, &N)
57}
58
59pub fn div_mod_n_packed_external_n(
60 vm: &mut VirtualMachine,
61 exec_scopes: &mut ExecutionScopes,
62 ids_data: &HashMap<String, HintReference>,
63 ap_tracking: &ApTracking,
64) -> Result<(), HintError> {
65 let n = exec_scopes.get::<BigInt>("N")?;
66 div_mod_n_packed(vm, exec_scopes, ids_data, ap_tracking, &n)
67}
68
69pub fn div_mod_n_safe_div(
72 exec_scopes: &mut ExecutionScopes,
73 a_alias: &str,
74 b_alias: &str,
75 to_add: u64,
76) -> Result<(), HintError> {
77 let a = exec_scopes.get_ref::<BigInt>(a_alias)?;
78 let b = exec_scopes.get_ref::<BigInt>(b_alias)?;
79 let res = exec_scopes.get_ref::<BigInt>("res")?;
80
81 let n = exec_scopes.get("N")?;
82
83 let value = safe_div_bigint(&(res * b - a), &n)?.add(to_add);
84
85 exec_scopes.insert_value("value", value);
86 Ok(())
87}
88
89pub fn get_point_from_x(
105 vm: &mut VirtualMachine,
106 exec_scopes: &mut ExecutionScopes,
107 ids_data: &HashMap<String, HintReference>,
108 ap_tracking: &ApTracking,
109 constants: &HashMap<String, Felt252>,
110) -> Result<(), HintError> {
111 exec_scopes.insert_value("SECP_P", SECP_P.clone());
112 let beta = constants
113 .get(BETA)
114 .ok_or_else(|| HintError::MissingConstant(Box::new(BETA)))?
115 .to_bigint();
116
117 let x_cube_int = Uint384::from_var_name("x_cube", vm, ids_data, ap_tracking)?
118 .pack86()
119 .mod_floor(&SECP_P);
120 let y_cube_int = (x_cube_int + beta).mod_floor(&SECP_P);
121 exec_scopes.insert_value("y_square_int", y_cube_int.clone());
122 let mut y = y_cube_int.modpow(&(&*SECP_P + 1_u32).shr(2_u32), &SECP_P);
124 exec_scopes.insert_value::<BigInt>("y", y.clone());
125
126 let v = get_integer_from_var_name("v", vm, ids_data, ap_tracking)?.to_bigint();
127 if v.is_even() != y.is_even() {
128 y = &*SECP_P - y;
129 }
130 exec_scopes.insert_value("value", y);
131 Ok(())
132}
133pub fn pack_modn_div_modn(
143 vm: &mut VirtualMachine,
144 exec_scopes: &mut ExecutionScopes,
145 ids_data: &HashMap<String, HintReference>,
146 ap_tracking: &ApTracking,
147) -> Result<(), HintError> {
148 let x = Uint384::from_var_name("x", vm, ids_data, ap_tracking)?
149 .pack86()
150 .mod_floor(&N);
151 let s = Uint384::from_var_name("s", vm, ids_data, ap_tracking)?
152 .pack86()
153 .mod_floor(&N);
154
155 let value = div_mod(&x, &s, &N)?;
156 exec_scopes.insert_value("x", x);
157 exec_scopes.insert_value("s", s);
158 exec_scopes.insert_value("N", N.clone());
159 exec_scopes.insert_value("value", value.clone());
160 exec_scopes.insert_value("res", value);
161 Ok(())
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use crate::stdlib::string::ToString;
168 use crate::types::errors::math_errors::MathError;
169
170 use crate::{
171 any_box,
172 hint_processor::{
173 builtin_hint_processor::{
174 builtin_hint_processor_definition::{BuiltinHintProcessor, HintProcessorData},
175 hint_code,
176 },
177 hint_processor_definition::HintProcessorLogic,
178 },
179 types::exec_scope::ExecutionScopes,
180 utils::test_utils::*,
181 };
182 use assert_matches::assert_matches;
183 use num_traits::{One, Zero};
184
185 #[cfg(target_arch = "wasm32")]
186 use wasm_bindgen_test::*;
187
188 #[test]
189 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
190 fn safe_div_ok() {
191 let mut exec_scopes = ExecutionScopes::new();
193 exec_scopes.assign_or_update_variable("N", any_box!(N.clone()));
194
195 let hint_codes = vec![
196 hint_code::DIV_MOD_N_PACKED_DIVMOD_V1,
197 hint_code::DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N,
198 ];
199 for hint_code in hint_codes {
200 let mut vm = vm!();
201
202 vm.segments = segments![
203 ((1, 0), 15),
204 ((1, 1), 3),
205 ((1, 2), 40),
206 ((1, 3), 0),
207 ((1, 4), 10),
208 ((1, 5), 1)
209 ];
210 vm.run_context.fp = 3;
211 let ids_data = non_continuous_ids_data![("a", -3), ("b", 0)];
212
213 assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(()));
214
215 assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "a", "b", 0), Ok(()));
216 assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "a", "b", 1), Ok(()));
217 }
218 }
219
220 #[test]
221 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
222 fn safe_div_fail() {
223 let mut exec_scopes = scope![
224 ("a", BigInt::zero()),
225 ("b", BigInt::one()),
226 ("res", BigInt::one()),
227 ("N", N.clone())
228 ];
229 assert_matches!(
230 div_mod_n_safe_div(
231 &mut exec_scopes,
232 "a",
233 "b",
234 0,
235 ),
236 Err(
237 HintError::Math(MathError::SafeDivFailBigInt(bx)
238 )) if *bx == (BigInt::one(), bigint_str!("115792089237316195423570985008687907852837564279074904382605163141518161494337"))
239 );
240 }
241
242 #[test]
243 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
244 fn get_point_from_x_ok() {
245 let hint_code = hint_code::GET_POINT_FROM_X;
246 let mut vm = vm!();
247 vm.segments = segments![
248 ((1, 0), 18),
249 ((1, 1), 2147483647),
250 ((1, 2), 2147483647),
251 ((1, 3), 2147483647)
252 ];
253 vm.run_context.fp = 1;
254 let ids_data = non_continuous_ids_data![("v", -1), ("x_cube", 0)];
255 assert_matches!(
256 run_hint!(
257 vm,
258 ids_data,
259 hint_code,
260 exec_scopes_ref!(),
261 &[(BETA, Felt252::from(7)),]
262 .into_iter()
263 .map(|(k, v)| (k.to_string(), v))
264 .collect()
265 ),
266 Ok(())
267 )
268 }
269
270 #[test]
271 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
272 fn get_point_from_x_negative_y() {
273 let hint_code = hint_code::GET_POINT_FROM_X;
274 let mut vm = vm!();
275 let mut exec_scopes = ExecutionScopes::new();
276 vm.segments = segments![
277 ((1, 0), 1),
278 ((1, 1), 2147483647),
279 ((1, 2), 2147483647),
280 ((1, 3), 2147483647)
281 ];
282 vm.run_context.fp = 2;
283
284 let ids_data = ids_data!["v", "x_cube"];
285 assert_matches!(
286 run_hint!(
287 vm,
288 ids_data,
289 hint_code,
290 &mut exec_scopes,
291 &[(BETA, Felt252::from(7)),]
292 .into_iter()
293 .map(|(k, v)| (k.to_string(), v))
294 .collect()
295 ),
296 Ok(())
297 );
298
299 check_scope!(
300 &exec_scopes,
301 [(
302 "value",
303 bigint_str!(
304 "94274691440067846579164151740284923997007081248613730142069408045642476712539"
305 )
306 )]
307 );
308 }
309
310 #[test]
311 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
312 fn pack_modn_div_modn_ok() {
313 let hint_code = hint_code::PACK_MODN_DIV_MODN;
314 let mut exec_scopes = scope![("N", N.clone())];
315 let mut vm = vm!();
316
317 vm.segments = segments![
318 ((1, 0), 15),
319 ((1, 1), 3),
320 ((1, 2), 40),
321 ((1, 3), 0),
322 ((1, 4), 10),
323 ((1, 5), 1)
324 ];
325 vm.run_context.fp = 3;
326 let ids_data = non_continuous_ids_data![("x", -3), ("s", 0)];
327 assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(()));
328 assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "x", "s", 0), Ok(()));
329 }
330}