1use crate::air_private_input::{PrivateInput, PrivateInputEcOp};
2use crate::stdlib::prelude::*;
3use crate::stdlib::{cell::RefCell, collections::HashMap};
4use crate::types::instance_definitions::ec_op_instance_def::{
5 CELLS_PER_EC_OP, INPUT_CELLS_PER_EC_OP, SCALAR_HEIGHT,
6};
7use crate::types::relocatable::{MaybeRelocatable, Relocatable};
8use crate::vm::errors::memory_errors::MemoryError;
9use crate::vm::errors::runner_errors::RunnerError;
10use crate::vm::vm_memory::memory::Memory;
11use crate::vm::vm_memory::memory_segments::MemorySegmentManager;
12use crate::Felt252;
13use num_integer::{div_ceil, Integer};
14use starknet_types_core::curve::ProjectivePoint;
15
16#[derive(Debug, Clone)]
17pub struct EcOpBuiltinRunner {
18 ratio: Option<u32>,
19 pub base: usize,
20 pub(crate) stop_ptr: Option<usize>,
21 pub(crate) included: bool,
22 cache: RefCell<HashMap<Relocatable, Felt252>>,
23}
24
25impl EcOpBuiltinRunner {
26 pub(crate) fn new(ratio: Option<u32>, included: bool) -> Self {
27 EcOpBuiltinRunner {
28 base: 0,
29 ratio,
30 stop_ptr: None,
31 included,
32 cache: RefCell::new(HashMap::new()),
33 }
34 }
35 fn point_on_curve(x: &Felt252, y: &Felt252, alpha: &Felt252, beta: &Felt252) -> bool {
39 y.pow(2_u32) == (x.pow(3_u32) + alpha * x) + beta
40 }
41
42 fn ec_op_impl(
49 partial_sum: (Felt252, Felt252),
50 doubled_point: (Felt252, Felt252),
51 m: &Felt252,
52 height: u32,
53 ) -> Result<(Felt252, Felt252), RunnerError> {
54 let slope = m.to_biguint();
55 let mut partial_sum_b = ProjectivePoint::from_affine(partial_sum.0, partial_sum.1)
56 .map_err(|_| RunnerError::PointNotOnCurve(Box::new(partial_sum)))?;
57 let mut doubled_point_b = ProjectivePoint::from_affine(doubled_point.0, doubled_point.1)
58 .map_err(|_| RunnerError::PointNotOnCurve(Box::new(doubled_point)))?;
59 for i in 0..(height as u64).min(slope.bits()) {
60 if partial_sum_b.x() * doubled_point_b.z() == partial_sum_b.z() * doubled_point_b.x() {
61 return Err(RunnerError::EcOpSameXCoordinate(
62 Self::format_ec_op_error(partial_sum_b, slope, doubled_point_b)
63 .into_boxed_str(),
64 ));
65 };
66 if slope.bit(i) {
67 partial_sum_b += &doubled_point_b;
68 }
69 doubled_point_b = doubled_point_b.double();
70 }
71 partial_sum_b
72 .to_affine()
73 .map(|p| (p.x(), p.y()))
74 .map_err(|_| RunnerError::InvalidPoint)
75 }
76
77 pub fn initialize_segments(&mut self, segments: &mut MemorySegmentManager) {
78 self.base = segments.add().segment_index as usize }
80
81 pub fn initial_stack(&self) -> Vec<MaybeRelocatable> {
82 if self.included {
83 vec![MaybeRelocatable::from((self.base as isize, 0))]
84 } else {
85 vec![]
86 }
87 }
88
89 pub fn base(&self) -> usize {
90 self.base
91 }
92
93 pub fn ratio(&self) -> Option<u32> {
94 self.ratio
95 }
96
97 pub fn deduce_memory_cell(
98 &self,
99 address: Relocatable,
100 memory: &Memory,
101 ) -> Result<Option<MaybeRelocatable>, RunnerError> {
102 const EC_POINT_INDICES: [(usize, usize); 3] = [(0, 1), (2, 3), (5, 6)];
104 const OUTPUT_INDICES: (usize, usize) = EC_POINT_INDICES[2];
105 let alpha: Felt252 = Felt252::ONE;
106 let beta_low: Felt252 = Felt252::from(0x609ad26c15c915c1f4cdfcb99cee9e89_u128);
107 let beta_high: Felt252 = Felt252::from(0x6f21413efbe40de150e596d72f7a8c5_u128);
108 let beta: Felt252 = (beta_high * (Felt252::ONE + Felt252::from(u128::MAX))) + beta_low;
109
110 let index = address.offset.mod_floor(&(CELLS_PER_EC_OP as usize));
111 if index != OUTPUT_INDICES.0 && index != OUTPUT_INDICES.1 {
113 return Ok(None);
114 }
115 let instance = Relocatable::from((address.segment_index, address.offset - index));
116 let x_addr = (instance + (&Felt252::from(INPUT_CELLS_PER_EC_OP)))
117 .map_err(|_| RunnerError::Memory(MemoryError::ExpectedInteger(Box::new(instance))))?;
118
119 if let Some(number) = self.cache.borrow().get(&address).cloned() {
120 return Ok(Some(MaybeRelocatable::Int(number)));
121 }
122
123 let mut input_cells = Vec::<Felt252>::with_capacity(INPUT_CELLS_PER_EC_OP as usize);
126 for i in 0..INPUT_CELLS_PER_EC_OP as usize {
127 match memory.get(&(instance + i)?) {
128 None => return Ok(None),
129 Some(addr) => {
130 input_cells.push(match addr.as_ref() {
131 MaybeRelocatable::Int(num) => *num,
132 _ => {
133 return Err(RunnerError::Memory(MemoryError::ExpectedInteger(
134 Box::new((instance + i)?),
135 )))
136 }
137 });
138 }
139 };
140 }
141 for pair in &EC_POINT_INDICES[0..2] {
150 if !EcOpBuiltinRunner::point_on_curve(
151 &input_cells[pair.0],
152 &input_cells[pair.1],
153 &alpha,
154 &beta,
155 ) {
156 return Err(RunnerError::PointNotOnCurve(Box::new((
157 input_cells[pair.0],
158 input_cells[pair.1],
159 ))));
160 };
161 }
162 let result = EcOpBuiltinRunner::ec_op_impl(
163 (input_cells[0].to_owned(), input_cells[1].to_owned()),
164 (input_cells[2].to_owned(), input_cells[3].to_owned()),
165 &input_cells[4],
166 SCALAR_HEIGHT,
167 )?;
168 self.cache.borrow_mut().insert(x_addr, result.0);
169 self.cache.borrow_mut().insert(
170 (x_addr + 1usize)
171 .map_err(|_| RunnerError::Memory(MemoryError::ExpectedInteger(Box::new(x_addr))))?,
172 result.1,
173 );
174 match index - INPUT_CELLS_PER_EC_OP as usize {
175 0 => Ok(Some(MaybeRelocatable::Int(result.0))),
176 _ => Ok(Some(MaybeRelocatable::Int(result.1))),
177 }
179 }
180
181 pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result<usize, MemoryError> {
182 segments
183 .get_segment_used_size(self.base())
184 .ok_or(MemoryError::MissingSegmentUsedSizes)
185 }
186
187 pub fn get_used_instances(
188 &self,
189 segments: &MemorySegmentManager,
190 ) -> Result<usize, MemoryError> {
191 let used_cells = self.get_used_cells(segments)?;
192 Ok(div_ceil(used_cells, CELLS_PER_EC_OP as usize))
193 }
194
195 pub fn format_ec_op_error(
196 p: ProjectivePoint,
197 m: num_bigint::BigUint,
198 q: ProjectivePoint,
199 ) -> String {
200 let p = p.to_affine().map(|p| (p.x(), p.y())).unwrap_or_default();
201 let q = q.to_affine().map(|q| (q.x(), q.y())).unwrap_or_default();
202 format!("Cannot apply EC operation: computation reached two points with the same x coordinate. \n
203 Attempting to compute P + m * Q where:\n
204 P = {p:?} \n
205 m = {m:?}\n
206 Q = {q:?}.")
207 }
208
209 pub fn air_private_input(&self, memory: &Memory) -> Vec<PrivateInput> {
210 let mut private_inputs = vec![];
211 if let Some(segment) = memory.data.get(self.base) {
212 let segment_len = segment.len();
213 for (index, off) in (0..segment_len)
214 .step_by(CELLS_PER_EC_OP as usize)
215 .enumerate()
216 {
217 if let (Ok(p_x), Ok(p_y), Ok(q_x), Ok(q_y), Ok(m)) = (
219 memory.get_integer((self.base as isize, off).into()),
220 memory.get_integer((self.base as isize, off + 1).into()),
221 memory.get_integer((self.base as isize, off + 2).into()),
222 memory.get_integer((self.base as isize, off + 3).into()),
223 memory.get_integer((self.base as isize, off + 4).into()),
224 ) {
225 private_inputs.push(PrivateInput::EcOp(PrivateInputEcOp {
226 index,
227 p_x: *p_x,
228 p_y: *p_y,
229 m: *m,
230 q_x: *q_x,
231 q_y: *q_y,
232 }))
233 }
234 }
235 }
236 private_inputs
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243 use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
244 use crate::types::builtin_name::BuiltinName;
245 use crate::types::layout_name::LayoutName;
246 use crate::types::program::Program;
247 use crate::utils::test_utils::*;
248 use crate::vm::errors::cairo_run_errors::CairoRunError;
249 use crate::vm::errors::vm_errors::VirtualMachineError;
250 use crate::{felt_hex, felt_str, relocatable};
251
252 use crate::vm::{
253 errors::{memory_errors::MemoryError, runner_errors::RunnerError},
254 runners::builtin_runner::BuiltinRunner,
255 };
256 use EcOpBuiltinRunner;
257
258 #[cfg(target_arch = "wasm32")]
259 use wasm_bindgen_test::*;
260
261 #[test]
262 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
263 fn get_used_instances() {
264 let builtin = EcOpBuiltinRunner::new(Some(10), true);
265
266 let mut vm = vm!();
267 vm.segments.segment_used_sizes = Some(vec![1]);
268
269 assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1));
270 }
271
272 #[test]
273 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
274 fn final_stack() {
275 let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into();
276
277 let mut vm = vm!();
278
279 vm.segments = segments![
280 ((0, 0), (0, 0)),
281 ((0, 1), (0, 1)),
282 ((2, 0), (0, 0)),
283 ((2, 1), (0, 0))
284 ];
285
286 vm.segments.segment_used_sizes = Some(vec![0]);
287
288 let pointer = Relocatable::from((2, 2));
289
290 assert_eq!(
291 builtin.final_stack(&vm.segments, pointer).unwrap(),
292 Relocatable::from((2, 1))
293 );
294 }
295
296 #[test]
297 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
298 fn final_stack_error_stop_pointer() {
299 let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into();
300
301 let mut vm = vm!();
302
303 vm.segments = segments![
304 ((0, 0), (0, 0)),
305 ((0, 1), (0, 1)),
306 ((2, 0), (0, 0)),
307 ((2, 1), (0, 0))
308 ];
309
310 vm.segments.segment_used_sizes = Some(vec![994]);
311
312 let pointer = Relocatable::from((2, 2));
313
314 assert_eq!(
315 builtin.final_stack(&vm.segments, pointer),
316 Err(RunnerError::InvalidStopPointer(Box::new((
317 BuiltinName::ec_op,
318 relocatable!(0, 994),
319 relocatable!(0, 0)
320 ))))
321 );
322 }
323
324 #[test]
325 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
326 fn final_stack_error_when_notincluded() {
327 let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), false).into();
328
329 let mut vm = vm!();
330
331 vm.segments = segments![
332 ((0, 0), (0, 0)),
333 ((0, 1), (0, 1)),
334 ((2, 0), (0, 0)),
335 ((2, 1), (0, 0))
336 ];
337
338 vm.segments.segment_used_sizes = Some(vec![0]);
339
340 let pointer = Relocatable::from((2, 2));
341
342 assert_eq!(
343 builtin.final_stack(&vm.segments, pointer).unwrap(),
344 Relocatable::from((2, 2))
345 );
346 }
347
348 #[test]
349 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
350 fn final_stack_error_non_relocatable() {
351 let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into();
352
353 let mut vm = vm!();
354
355 vm.segments = segments![
356 ((0, 0), (0, 0)),
357 ((0, 1), (0, 1)),
358 ((2, 0), (0, 0)),
359 ((2, 1), 2)
360 ];
361
362 vm.segments.segment_used_sizes = Some(vec![0]);
363
364 let pointer = Relocatable::from((2, 2));
365
366 assert_eq!(
367 builtin.final_stack(&vm.segments, pointer),
368 Err(RunnerError::NoStopPointer(Box::new(BuiltinName::ec_op)))
369 );
370 }
371
372 #[test]
373 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
374 fn get_used_cells_and_allocated_size_test() {
375 let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into();
376
377 let program = program!(
378 builtins = vec![BuiltinName::pedersen],
379 data = vec_data!(
380 (4612671182993129469_i64),
381 (5189976364521848832_i64),
382 (18446744073709551615_i128),
383 (5199546496550207487_i64),
384 (4612389712311386111_i64),
385 (5198983563776393216_i64),
386 (2),
387 (2345108766317314046_i64),
388 (5191102247248822272_i64),
389 (5189976364521848832_i64),
390 (7),
391 (1226245742482522112_i64),
392 ((
393 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
394 10
395 )),
396 (2345108766317314046_i64)
397 ),
398 main = Some(8),
399 );
400 let mut cairo_runner = cairo_runner!(program);
401
402 cairo_runner.vm.segments.segment_used_sizes = Some(vec![0]);
403
404 let mut hint_processor = BuiltinHintProcessor::new_empty();
405
406 let address = cairo_runner.initialize(false).unwrap();
407
408 cairo_runner
409 .run_until_pc(address, &mut hint_processor)
410 .unwrap();
411
412 assert_eq!(
413 builtin.get_used_cells_and_allocated_size(&cairo_runner.vm),
414 Ok((0, 7))
415 );
416 }
417
418 #[test]
419 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
420 fn get_allocated_memory_units() {
421 let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into();
422
423 let program = program!(
424 builtins = vec![BuiltinName::ec_op],
425 data = vec_data!(
426 (4612671182993129469_i64),
427 (5189976364521848832_i64),
428 (18446744073709551615_i128),
429 (5199546496550207487_i64),
430 (4612389712311386111_i64),
431 (5198983563776393216_i64),
432 (2),
433 (2345108766317314046_i64),
434 (5191102247248822272_i64),
435 (5189976364521848832_i64),
436 (7),
437 (1226245742482522112_i64),
438 ((
439 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
440 10
441 )),
442 (2345108766317314046_i64)
443 ),
444 main = Some(8),
445 );
446
447 let mut cairo_runner = cairo_runner!(program);
448
449 let mut hint_processor = BuiltinHintProcessor::new_empty();
450
451 let address = cairo_runner.initialize(false).unwrap();
452
453 cairo_runner
454 .run_until_pc(address, &mut hint_processor)
455 .unwrap();
456
457 assert_eq!(builtin.get_allocated_memory_units(&cairo_runner.vm), Ok(7));
458 }
459
460 #[test]
461 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
462 fn point_is_on_curve_a() {
463 let x = felt_hex!("0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca");
464 let y = felt_hex!("0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f");
465 let alpha = Felt252::ONE;
466 let beta = felt_hex!("0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89");
467 assert!(EcOpBuiltinRunner::point_on_curve(&x, &y, &alpha, &beta));
468 }
469
470 #[test]
471 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
472 fn point_is_on_curve_b() {
473 let x = felt_hex!("0x6f0a1ddaf19c44781c8946db396f494a10ffab183c2d8cf6c4cd321a8d87fd9");
474 let y = felt_hex!("0x4afa52a9ef8c023d3385fddb6e1d78d57b0693b9b02d45d0f939b526d474c39");
475 let alpha = Felt252::ONE;
476 let beta = felt_hex!("0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89");
477 assert!(EcOpBuiltinRunner::point_on_curve(&x, &y, &alpha, &beta));
478 }
479
480 #[test]
481 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
482 fn point_is_not_on_curve_a() {
483 let x = felt_hex!("0x1ef15c1a2162fb0d2e5d83196a6fb0509632fab5d746f0c3d723d8bc943cfca");
484 let y = felt_hex!("0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f");
485 let alpha = Felt252::ONE;
486 let beta = felt_hex!("0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89");
487 assert!(!EcOpBuiltinRunner::point_on_curve(&x, &y, &alpha, &beta));
488 }
489
490 #[test]
491 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
492 fn point_is_not_on_curve_b() {
493 let x = felt_hex!("0x6f0a1ddaeb88837dcc8ac9a48f894deed706bc3e8998e63535e2c91a8d87fd9");
494 let y = felt_hex!("0x4afa52a9ef8c023d33ea3865fb4e0e49abfc50dd50ccea867539b526d474c39");
495 let alpha = Felt252::ONE;
496 let beta = felt_hex!("0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89");
497 assert!(!EcOpBuiltinRunner::point_on_curve(&x, &y, &alpha, &beta));
498 }
499
500 #[test]
501 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
502 fn compute_ec_op_impl_valid_a() {
503 let partial_sum = (
504 felt_hex!("0x6f0a1ddaf19c44781c8946db396f494a10ffab183c2d8cf6c4cd321a8d87fd9"),
505 felt_hex!("0x4afa52a9ef8c023d3385fddb6e1d78d57b0693b9b02d45d0f939b526d474c39"),
506 );
507 let doubled_point = (
508 felt_hex!("0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca"),
509 felt_hex!("0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f"),
510 );
511 let m = Felt252::from(34);
512 let height = 256;
513 let result = EcOpBuiltinRunner::ec_op_impl(partial_sum, doubled_point, &m, height);
514 assert_eq!(
515 result,
516 Ok((
517 felt_str!(
518 "1977874238339000383330315148209250828062304908491266318460063803060754089297"
519 ),
520 felt_str!(
521 "2969386888251099938335087541720168257053975603483053253007176033556822156706"
522 )
523 ))
524 );
525 }
526
527 #[test]
528 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
529 fn compute_ec_op_impl_valid_b() {
530 let partial_sum = (
531 felt_hex!("0x68caa9509b7c2e90b4d92661cbf7c465471c1e8598c5f989691eef6653e0f38"),
532 felt_hex!("0x79a8673f498531002fc549e06ff2010ffc0c191cceb7da5532acb95cdcb591"),
533 );
534 let doubled_point = (
535 felt_hex!("0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca"),
536 felt_hex!("0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f"),
537 );
538 let m = Felt252::from(34);
539 let height = 256;
540 let result = EcOpBuiltinRunner::ec_op_impl(partial_sum, doubled_point, &m, height);
541 assert_eq!(
542 result,
543 Ok((
544 felt_str!(
545 "2778063437308421278851140253538604815869848682781135193774472480292420096757"
546 ),
547 felt_str!(
548 "3598390311618116577316045819420613574162151407434885460365915347732568210029"
549 )
550 ))
551 );
552 }
553
554 #[test]
555 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
556 fn compute_ec_op_invalid_same_x_coordinate() {
557 let partial_sum = (
558 felt_hex!("0x6f0a1ddaf19c44781c8946db396f494a10ffab183c2d8cf6c4cd321a8d87fd9"),
559 felt_hex!("0x4afa52a9ef8c023d3385fddb6e1d78d57b0693b9b02d45d0f939b526d474c39"),
560 );
561 let doubled_point = (
562 felt_hex!("0x6f0a1ddaf19c44781c8946db396f494a10ffab183c2d8cf6c4cd321a8d87fd9"),
563 felt_hex!("0x4afa52a9ef8c023d3385fddb6e1d78d57b0693b9b02d45d0f939b526d474c39"),
564 );
565 let m = Felt252::from(34);
566 let height = 256;
567 let result = EcOpBuiltinRunner::ec_op_impl(partial_sum, doubled_point, &m, height);
568 assert_eq!(
569 result,
570 Err(RunnerError::EcOpSameXCoordinate(
571 EcOpBuiltinRunner::format_ec_op_error(
572 ProjectivePoint::from_affine(partial_sum.0, partial_sum.1).unwrap(),
573 m.to_biguint(),
574 ProjectivePoint::from_affine(doubled_point.0, doubled_point.1).unwrap(),
575 )
576 .into_boxed_str()
577 ))
578 );
579 }
580
581 #[test]
582 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
583 fn deduce_memory_cell_ec_op_for_preset_memory_valid() {
600 let memory = memory![
601 (
602 (3, 0),
603 (
604 "0x68caa9509b7c2e90b4d92661cbf7c465471c1e8598c5f989691eef6653e0f38",
605 16
606 )
607 ),
608 (
609 (3, 1),
610 (
611 "0x79a8673f498531002fc549e06ff2010ffc0c191cceb7da5532acb95cdcb591",
612 16
613 )
614 ),
615 (
616 (3, 2),
617 (
618 "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
619 16
620 )
621 ),
622 (
623 (3, 3),
624 (
625 "0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f",
626 16
627 )
628 ),
629 ((3, 4), 34),
630 (
631 (3, 5),
632 (
633 "2778063437308421278851140253538604815869848682781135193774472480292420096757",
634 10
635 )
636 )
637 ];
638 let builtin = EcOpBuiltinRunner::new(Some(256), true);
639
640 let result = builtin.deduce_memory_cell(Relocatable::from((3, 6)), &memory);
641 assert_eq!(
642 result,
643 Ok(Some(MaybeRelocatable::from(felt_str!(
644 "3598390311618116577316045819420613574162151407434885460365915347732568210029"
645 ))))
646 );
647 }
648
649 #[test]
650 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
651 fn deduce_memory_cell_ec_op_for_preset_memory_unfilled_input_cells() {
652 let memory = memory![
653 (
654 (3, 1),
655 (
656 "0x79a8673f498531002fc549e06ff2010ffc0c191cceb7da5532acb95cdcb591",
657 16
658 )
659 ),
660 (
661 (3, 2),
662 (
663 "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
664 16
665 )
666 ),
667 (
668 (3, 3),
669 (
670 "0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f",
671 16
672 )
673 ),
674 ((3, 4), 34),
675 (
676 (3, 5),
677 (
678 "2778063437308421278851140253538604815869848682781135193774472480292420096757",
679 10
680 )
681 )
682 ];
683
684 let builtin = EcOpBuiltinRunner::new(Some(256), true);
685 let result = builtin.deduce_memory_cell(Relocatable::from((3, 6)), &memory);
686 assert_eq!(result, Ok(None));
687 }
688
689 #[test]
690 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
691 fn deduce_memory_cell_ec_op_for_preset_memory_addr_not_an_output_cell() {
692 let memory = memory![
693 (
694 (3, 0),
695 (
696 "0x68caa9509b7c2e90b4d92661cbf7c465471c1e8598c5f989691eef6653e0f38",
697 16
698 )
699 ),
700 (
701 (3, 1),
702 (
703 "0x79a8673f498531002fc549e06ff2010ffc0c191cceb7da5532acb95cdcb591",
704 16
705 )
706 ),
707 (
708 (3, 2),
709 (
710 "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
711 16
712 )
713 ),
714 (
715 (3, 3),
716 (
717 "0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f",
718 16
719 )
720 ),
721 ((3, 4), 34),
722 (
723 (3, 5),
724 (
725 "2778063437308421278851140253538604815869848682781135193774472480292420096757",
726 10
727 )
728 )
729 ];
730 let builtin = EcOpBuiltinRunner::new(Some(256), true);
731
732 let result = builtin.deduce_memory_cell(Relocatable::from((3, 3)), &memory);
733 assert_eq!(result, Ok(None));
734 }
735
736 #[test]
737 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
738 fn deduce_memory_cell_ec_op_for_preset_memory_non_integer_input() {
739 let memory = memory![
740 (
741 (3, 0),
742 (
743 "0x68caa9509b7c2e90b4d92661cbf7c465471c1e8598c5f989691eef6653e0f38",
744 16
745 )
746 ),
747 (
748 (3, 1),
749 (
750 "0x79a8673f498531002fc549e06ff2010ffc0c191cceb7da5532acb95cdcb591",
751 16
752 )
753 ),
754 (
755 (3, 2),
756 (
757 "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
758 16
759 )
760 ),
761 ((3, 3), (1, 2)),
762 ((3, 4), 34),
763 (
764 (3, 5),
765 (
766 "2778063437308421278851140253538604815869848682781135193774472480292420096757",
767 10
768 )
769 )
770 ];
771 let builtin = EcOpBuiltinRunner::new(Some(256), true);
772
773 assert_eq!(
774 builtin.deduce_memory_cell(Relocatable::from((3, 6)), &memory),
775 Err(RunnerError::Memory(MemoryError::ExpectedInteger(Box::new(
776 Relocatable::from((3, 3))
777 ))))
778 );
779 }
780
781 #[test]
782 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
783 fn get_used_cells_missing_segment_used_sizes() {
784 let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true));
785 let vm = vm!();
786
787 assert_eq!(
788 builtin.get_used_cells(&vm.segments),
789 Err(MemoryError::MissingSegmentUsedSizes)
790 );
791 }
792
793 #[test]
794 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
795 fn get_used_cells_empty() {
796 let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true));
797 let mut vm = vm!();
798
799 vm.segments.segment_used_sizes = Some(vec![0]);
800 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0));
801 }
802
803 #[test]
804 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
805 fn get_used_cells() {
806 let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true));
807 let mut vm = vm!();
808
809 vm.segments.segment_used_sizes = Some(vec![4]);
810 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4));
811 }
812
813 #[test]
814 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
815 fn initial_stackincluded_test() {
816 let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into();
817 assert_eq!(ec_op_builtin.initial_stack(), vec![mayberelocatable!(0, 0)])
818 }
819
820 #[test]
821 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
822 fn initial_stack_notincluded_test() {
823 let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), false);
824 assert_eq!(ec_op_builtin.initial_stack(), Vec::new())
825 }
826
827 #[test]
828 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
829 fn catch_point_same_x() {
830 let program =
831 include_bytes!("../../../../../cairo_programs/bad_programs/ec_op_same_x.json");
832 let cairo_run_config = crate::cairo_run::CairoRunConfig {
833 layout: LayoutName::all_cairo,
834 ..crate::cairo_run::CairoRunConfig::default()
835 };
836 let result = crate::cairo_run::cairo_run(
837 program,
838 &cairo_run_config,
839 &mut BuiltinHintProcessor::new_empty(),
840 );
841 assert!(result.is_err());
842 match result {
844 Err(CairoRunError::VirtualMachine(VirtualMachineError::RunnerError(
845 RunnerError::EcOpSameXCoordinate(_),
846 ))) => {}
847 Err(_) => panic!("Wrong error returned, expected RunnerError::EcOpSameXCoordinate"),
848 Ok(_) => panic!("Expected run to fail"),
849 }
850 }
851
852 #[test]
853 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
854 fn catch_point_not_in_curve() {
855 let program =
856 include_bytes!("../../../../../cairo_programs/bad_programs/ec_op_not_in_curve.json");
857 let cairo_run_config = crate::cairo_run::CairoRunConfig {
858 layout: LayoutName::all_cairo,
859 ..crate::cairo_run::CairoRunConfig::default()
860 };
861 let result = crate::cairo_run::cairo_run(
862 program,
863 &cairo_run_config,
864 &mut BuiltinHintProcessor::new_empty(),
865 );
866 assert!(result.is_err());
867
868 match result {
870 Err(CairoRunError::VirtualMachine(VirtualMachineError::RunnerError(
871 RunnerError::PointNotOnCurve(_),
872 ))) => {}
873 Err(_) => panic!("Wrong error returned, expected RunnerError::EcOpSameXCoordinate"),
874 Ok(_) => panic!("Expected run to fail"),
875 }
876 }
877
878 #[test]
879 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
880 fn get_air_private_input() {
881 let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into();
882
883 let segments = segments![
884 ((0, 0), 0),
885 ((0, 1), 1),
886 ((0, 2), 2),
887 ((0, 3), 3),
888 ((0, 4), 4)
889 ];
890 assert_eq!(
891 builtin.air_private_input(&segments),
892 (vec![PrivateInput::EcOp(PrivateInputEcOp {
893 index: 0,
894 p_x: 0.into(),
895 p_y: 1.into(),
896 m: 4.into(),
897 q_x: 2.into(),
898 q_y: 3.into(),
899 })])
900 );
901 }
902}