1use crate::air_private_input::{PrivateInput, PrivateInputSignature, SignatureInput};
2use crate::math_utils::div_mod;
3use crate::stdlib::{cell::RefCell, collections::HashMap, prelude::*, rc::Rc};
4
5use crate::types::builtin_name::BuiltinName;
6use crate::types::instance_definitions::ecdsa_instance_def::CELLS_PER_SIGNATURE;
7use crate::vm::errors::runner_errors::RunnerError;
8use crate::vm::runners::cairo_pie::BuiltinAdditionalData;
9use crate::Felt252;
10use crate::{
11 types::relocatable::{MaybeRelocatable, Relocatable},
12 vm::{
13 errors::memory_errors::MemoryError,
14 vm_memory::{
15 memory::{Memory, ValidationRule},
16 memory_segments::MemorySegmentManager,
17 },
18 },
19};
20use lazy_static::lazy_static;
21use num_bigint::{BigInt, Sign};
22use num_integer::div_ceil;
23use num_traits::{Num, One};
24use starknet_crypto::{verify, Signature};
25
26lazy_static! {
27 static ref EC_ORDER: BigInt = BigInt::from_str_radix(
28 "3618502788666131213697322783095070105526743751716087489154079457884512865583",
29 10
30 )
31 .unwrap();
32}
33
34#[derive(Debug, Clone)]
35pub struct SignatureBuiltinRunner {
36 pub(crate) included: bool,
37 ratio: Option<u32>,
38 base: usize,
39 pub(crate) stop_ptr: Option<usize>,
40 signatures: Rc<RefCell<HashMap<Relocatable, Signature>>>,
41}
42
43impl SignatureBuiltinRunner {
44 pub(crate) fn new(ratio: Option<u32>, included: bool) -> Self {
45 SignatureBuiltinRunner {
46 base: 0,
47 included,
48 ratio,
49 stop_ptr: None,
50 signatures: Rc::new(RefCell::new(HashMap::new())),
51 }
52 }
53
54 pub fn add_signature(
55 &mut self,
56 relocatable: Relocatable,
57 (r, s): &(Felt252, Felt252),
58 ) -> Result<(), MemoryError> {
59 let r_be_bytes = r.to_bytes_be();
60 let s_be_bytes = s.to_bytes_be();
61 let (r_felt, s_felt) = (
62 Felt252::from_bytes_be(&r_be_bytes),
63 Felt252::from_bytes_be(&s_be_bytes),
64 );
65
66 let signature = Signature {
67 r: r_felt,
68 s: s_felt,
69 };
70
71 self.signatures
72 .borrow_mut()
73 .entry(relocatable)
74 .or_insert(signature);
75
76 Ok(())
77 }
78}
79
80impl SignatureBuiltinRunner {
81 pub fn initialize_segments(&mut self, segments: &mut MemorySegmentManager) {
82 self.base = segments.add().segment_index as usize }
84
85 pub fn initial_stack(&self) -> Vec<MaybeRelocatable> {
86 if self.included {
87 vec![MaybeRelocatable::from((self.base as isize, 0))]
88 } else {
89 vec![]
90 }
91 }
92
93 pub fn base(&self) -> usize {
94 self.base
95 }
96 pub fn add_validation_rule(&self, memory: &mut Memory) {
97 let cells_per_instance = CELLS_PER_SIGNATURE;
98 let signatures = Rc::clone(&self.signatures);
99 let rule: ValidationRule = ValidationRule(Box::new(
100 move |memory: &Memory, addr: Relocatable| -> Result<Vec<Relocatable>, MemoryError> {
101 let cell_index = addr.offset % cells_per_instance as usize;
102
103 let (pubkey_addr, message_addr) = match cell_index {
104 0 => (addr, (addr + 1)?),
105 1 => match addr - 1 {
106 Ok(prev_addr) => (prev_addr, addr),
107 Err(_) => return Ok(vec![]),
108 },
109 _ => return Ok(vec![]),
110 };
111
112 let pubkey = match memory.get_integer(pubkey_addr) {
113 Ok(num) => num,
114 Err(_) if cell_index == 1 => return Ok(vec![]),
115 _ => return Err(MemoryError::PubKeyNonInt(Box::new(pubkey_addr))),
116 };
117
118 let msg = match memory.get_integer(message_addr) {
119 Ok(num) => num,
120 Err(_) if cell_index == 0 => return Ok(vec![]),
121 _ => return Err(MemoryError::MsgNonInt(Box::new(message_addr))),
122 };
123
124 let signatures_map = signatures.borrow();
125 let signature = signatures_map
126 .get(&pubkey_addr)
127 .ok_or_else(|| MemoryError::SignatureNotFound(Box::new(pubkey_addr)))?;
128
129 let public_key = Felt252::from_bytes_be(&pubkey.to_bytes_be());
130 let (r, s) = (signature.r, signature.s);
131 let message = Felt252::from_bytes_be(&msg.to_bytes_be());
132 match verify(&public_key, &message, &r, &s) {
133 Ok(true) => Ok(vec![]),
134 _ => Err(MemoryError::InvalidSignature(Box::new((
135 format!("({}, {})", signature.r, signature.s),
136 pubkey.into_owned(),
137 msg.into_owned(),
138 )))),
139 }
140 },
141 ));
142 memory.add_validation_rule(self.base, rule);
143 }
144
145 pub fn ratio(&self) -> Option<u32> {
146 self.ratio
147 }
148
149 pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result<usize, MemoryError> {
150 segments
151 .get_segment_used_size(self.base)
152 .ok_or(MemoryError::MissingSegmentUsedSizes)
153 }
154
155 pub fn get_used_instances(
156 &self,
157 segments: &MemorySegmentManager,
158 ) -> Result<usize, MemoryError> {
159 let used_cells = self.get_used_cells(segments)?;
160 Ok(div_ceil(used_cells, CELLS_PER_SIGNATURE as usize))
161 }
162
163 pub fn get_additional_data(&self) -> BuiltinAdditionalData {
164 let signatures: HashMap<Relocatable, (Felt252, Felt252)> = self
166 .signatures
167 .borrow()
168 .iter()
169 .map(|(k, v)| {
170 (
171 *k,
172 (
173 Felt252::from_bytes_be(&v.r.to_bytes_be()),
174 Felt252::from_bytes_be(&v.s.to_bytes_be()),
175 ),
176 )
177 })
178 .collect();
179 BuiltinAdditionalData::Signature(signatures)
180 }
181
182 pub fn extend_additional_data(
183 &mut self,
184 additional_data: &BuiltinAdditionalData,
185 ) -> Result<(), RunnerError> {
186 let additional_data = match additional_data {
187 BuiltinAdditionalData::Signature(d) => d,
188 BuiltinAdditionalData::Empty(_) => return Ok(()),
189 _ => return Err(RunnerError::InvalidAdditionalData(BuiltinName::ecdsa)),
190 };
191 for (addr, (r, s)) in additional_data {
192 if addr.segment_index != self.base as isize {
193 return Err(RunnerError::InvalidAdditionalData(BuiltinName::ecdsa));
194 }
195 self.signatures.borrow_mut().insert(
196 *addr,
197 Signature {
198 r: Felt252::from_bytes_be(&r.to_bytes_be()),
199 s: Felt252::from_bytes_be(&s.to_bytes_be()),
200 },
201 );
202 }
203 Ok(())
204 }
205
206 pub fn air_private_input(&self, memory: &Memory) -> Vec<PrivateInput> {
207 let mut private_inputs = vec![];
208
209 let binding = self.signatures.borrow();
211 let mut sorted_signatures: Vec<_> = binding.iter().collect();
212 sorted_signatures.sort_by_key(|(addr, _)| {
213 addr.offset
214 .checked_div(CELLS_PER_SIGNATURE as usize)
215 .unwrap_or_default()
216 });
217
218 for (addr, signature) in sorted_signatures {
219 if let (Ok(pubkey), Some(msg)) = (
220 memory.get_integer(*addr),
221 (*addr + 1_usize)
222 .ok()
223 .and_then(|addr| memory.get_integer(addr).ok()),
224 ) {
225 private_inputs.push(PrivateInput::Signature(PrivateInputSignature {
226 index: addr
227 .offset
228 .checked_div(CELLS_PER_SIGNATURE as usize)
229 .unwrap_or_default(),
230 pubkey: *pubkey,
231 msg: *msg,
232 signature_input: SignatureInput {
233 r: Felt252::from_bytes_be(&signature.r.to_bytes_be()),
234 w: Felt252::from(
235 &div_mod(
236 &BigInt::one(),
237 &BigInt::from_bytes_be(Sign::Plus, &signature.s.to_bytes_be()),
238 &EC_ORDER,
239 )
240 .unwrap_or_default(),
241 ),
242 },
243 }))
244 }
245 }
246 private_inputs
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253 use crate::{
254 relocatable,
255 types::builtin_name::BuiltinName,
256 utils::test_utils::*,
257 vm::{
258 errors::{
259 memory_errors::{InsufficientAllocatedCellsError, MemoryError},
260 runner_errors::RunnerError,
261 },
262 runners::builtin_runner::BuiltinRunner,
263 vm_memory::{memory::Memory, memory_segments::MemorySegmentManager},
264 },
265 };
266
267 use crate::felt_str;
268 #[cfg(target_arch = "wasm32")]
269 use wasm_bindgen_test::*;
270
271 #[test]
272 fn get_used_cells_and_allocated_size_valid() {
273 let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(10), true).into();
274 let mut vm = vm!();
275 vm.current_step = 110;
276 vm.segments.segment_used_sizes = Some(vec![1]);
277 assert_eq!(builtin.get_used_cells_and_allocated_size(&vm), Ok((1, 22)));
278 }
279
280 #[test]
281 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
282 fn initialize_segments_for_ecdsa() {
283 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
284 let mut segments = MemorySegmentManager::new();
285 builtin.initialize_segments(&mut segments);
286 assert_eq!(builtin.base, 0);
287 }
288
289 #[test]
290 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
291 fn get_used_instances() {
292 let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
293
294 let mut vm = vm!();
295 vm.segments.segment_used_sizes = Some(vec![1]);
296
297 assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1));
298 }
299
300 #[test]
301 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
302 fn final_stack() {
303 let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
304
305 let mut vm = vm!();
306
307 vm.segments = segments![
308 ((0, 0), (0, 0)),
309 ((0, 1), (0, 1)),
310 ((2, 0), (0, 0)),
311 ((2, 1), (0, 0))
312 ];
313
314 vm.segments.segment_used_sizes = Some(vec![0]);
315
316 let pointer = Relocatable::from((2, 2));
317
318 assert_eq!(
319 builtin.final_stack(&vm.segments, pointer).unwrap(),
320 Relocatable::from((2, 1))
321 );
322 }
323
324 #[test]
325 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
326 fn final_stack_error_stop_pointer() {
327 let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).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![998]);
339
340 let pointer = Relocatable::from((2, 2));
341
342 assert_eq!(
343 builtin.final_stack(&vm.segments, pointer),
344 Err(RunnerError::InvalidStopPointer(Box::new((
345 BuiltinName::ecdsa,
346 relocatable!(0, 998),
347 relocatable!(0, 0)
348 ))))
349 );
350 }
351
352 #[test]
353 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
354 fn final_stack_error_non_relocatable() {
355 let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
356
357 let mut vm = vm!();
358
359 vm.segments = segments![
360 ((0, 0), (0, 0)),
361 ((0, 1), (0, 1)),
362 ((2, 0), (0, 0)),
363 ((2, 1), 2)
364 ];
365
366 vm.segments.segment_used_sizes = Some(vec![0]);
367
368 let pointer = Relocatable::from((2, 2));
369
370 assert_eq!(
371 builtin.final_stack(&vm.segments, pointer),
372 Err(RunnerError::NoStopPointer(Box::new(BuiltinName::ecdsa)))
373 );
374 }
375
376 #[test]
377 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
378 fn get_used_cells_missing_segment_used_sizes() {
379 let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), true));
380 let vm = vm!();
381
382 assert_eq!(
383 builtin.get_used_cells(&vm.segments),
384 Err(MemoryError::MissingSegmentUsedSizes)
385 );
386 }
387
388 #[test]
389 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
390 fn get_used_cells_empty() {
391 let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), true));
392 let mut vm = vm!();
393
394 vm.segments.segment_used_sizes = Some(vec![0]);
395 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0));
396 }
397
398 #[test]
399 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
400 fn get_used_cells() {
401 let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), true));
402 let mut vm = vm!();
403
404 vm.segments.segment_used_sizes = Some(vec![4]);
405 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4));
406 }
407
408 #[test]
409 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
410 fn get_initial_stack_for_range_check_with_base() {
411 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
412 builtin.base = 1;
413 let initial_stack = builtin.initial_stack();
414 assert_eq!(
415 initial_stack[0].clone(),
416 MaybeRelocatable::RelocatableValue((builtin.base() as isize, 0).into())
417 );
418 assert_eq!(initial_stack.len(), 1);
419 }
420
421 #[test]
422 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
423 fn initial_stack_not_included_test() {
424 let ecdsa_builtin = SignatureBuiltinRunner::new(Some(512), false);
425 assert_eq!(ecdsa_builtin.initial_stack(), Vec::new())
426 }
427
428 #[test]
429 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
430 fn deduce_memory_cell_test() {
431 let memory = Memory::new();
432 let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
433 let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory);
434 assert_eq!(result, Ok(None));
435 }
436
437 #[test]
438 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
439 fn test_ratio() {
440 let builtin = SignatureBuiltinRunner::new(Some(512), true);
441 assert_eq!(builtin.ratio(), Some(512));
442 }
443
444 #[test]
445 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
446 fn test_base() {
447 let builtin = SignatureBuiltinRunner::new(Some(512), true);
448 assert_eq!(builtin.base(), 0);
449 }
450
451 #[test]
452 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
453 fn get_allocated_memory_min_step_not_reached() {
454 let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
455 let mut vm = vm!();
456 vm.current_step = 500;
457 assert_eq!(
458 builtin.get_allocated_memory_units(&vm),
459 Err(MemoryError::InsufficientAllocatedCells(
460 InsufficientAllocatedCellsError::MinStepNotReached(Box::new((
461 512,
462 BuiltinName::ecdsa
463 )))
464 ))
465 )
466 }
467
468 #[test]
469 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
470 fn get_used_cells_and_allocated_size_insufficient_allocated() {
471 let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
472 let mut vm = vm!();
473 vm.segments.segment_used_sizes = Some(vec![50]);
474 vm.current_step = 512;
475 assert_eq!(
476 builtin.get_used_cells_and_allocated_size(&vm),
477 Err(MemoryError::InsufficientAllocatedCells(
478 InsufficientAllocatedCellsError::BuiltinCells(Box::new((
479 BuiltinName::ecdsa,
480 50,
481 2
482 )))
483 ))
484 )
485 }
486
487 #[test]
488 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
489 fn final_stack_invalid_stop_pointer() {
490 let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
491 let mut vm = vm!();
492 vm.segments = segments![((0, 0), (1, 0))];
493 assert_eq!(
494 builtin.final_stack(&vm.segments, (0, 1).into()),
495 Err(RunnerError::InvalidStopPointerIndex(Box::new((
496 BuiltinName::ecdsa,
497 relocatable!(1, 0),
498 0
499 ))))
500 )
501 }
502
503 #[test]
504 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
505 fn final_stack_no_used_instances() {
506 let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into();
507 let mut vm = vm!();
508 vm.segments = segments![((0, 0), (0, 0))];
509 assert_eq!(
510 builtin.final_stack(&vm.segments, (0, 1).into()),
511 Err(RunnerError::Memory(MemoryError::MissingSegmentUsedSizes))
512 )
513 }
514
515 #[test]
516 fn get_additional_data() {
517 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
518 let signatures = HashMap::from([(
519 Relocatable::from((4, 0)),
520 Signature {
521 r: Felt252::from_dec_str("45678").unwrap(),
522 s: Felt252::from_dec_str("1239").unwrap(),
523 },
524 )]);
525 builtin.signatures = Rc::new(RefCell::new(signatures));
526 let signatures = HashMap::from([(
527 Relocatable::from((4, 0)),
528 (felt_str!("45678"), felt_str!("1239")),
529 )]);
530 assert_eq!(
531 builtin.get_additional_data(),
532 BuiltinAdditionalData::Signature(signatures)
533 )
534 }
535
536 #[test]
537 fn get_and_extend_additional_data() {
538 let mut builtin_a = SignatureBuiltinRunner::new(Some(512), true);
539 let signatures = HashMap::from([(
540 Relocatable::from((0, 0)),
541 Signature {
542 r: Felt252::from_dec_str("45678").unwrap(),
543 s: Felt252::from_dec_str("1239").unwrap(),
544 },
545 )]);
546 builtin_a.signatures = Rc::new(RefCell::new(signatures));
547 let additional_data = builtin_a.get_additional_data();
548 let mut builtin_b = SignatureBuiltinRunner::new(Some(512), true);
549 builtin_b.extend_additional_data(&additional_data).unwrap();
550 let signatures_a = builtin_a.signatures.borrow();
552 let signatures_b = builtin_b.signatures.borrow();
553 assert_eq!(signatures_a.len(), signatures_b.len());
554 for ((addr_a, signature_a), (addr_b, signature_b)) in
555 signatures_a.iter().zip(signatures_b.iter())
556 {
557 assert_eq!(addr_a, addr_b);
558 assert_eq!(signature_a.r, signature_b.r);
559 assert_eq!(signature_a.s, signature_b.s);
560 }
561 }
562 #[test]
563 fn get_air_private_input() {
564 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
565
566 builtin.base = 0;
567
568 let signature1_r = Felt252::from(1234);
569 let signature1_s = Felt252::from(5678);
570 let signature2_r = Felt252::from(8765);
571 let signature2_s = Felt252::from(4321);
572
573 let sig1_addr = Relocatable::from((builtin.base as isize, 0));
574 let sig2_addr = Relocatable::from((builtin.base as isize, CELLS_PER_SIGNATURE as usize));
575
576 builtin
577 .add_signature(sig1_addr, &(signature1_r, signature1_s))
578 .unwrap();
579 builtin
580 .add_signature(sig2_addr, &(signature2_r, signature2_s))
581 .unwrap();
582
583 let pubkey1 = Felt252::from(1111);
584 let msg1 = Felt252::from(2222);
585 let pubkey2 = Felt252::from(3333);
586 let msg2 = Felt252::from(4444);
587
588 let segments = segments![
589 ((0, 0), 1111),
590 ((0, 1), 2222),
591 ((0, 2), 3333),
592 ((0, 3), 4444)
593 ];
594 let w1 =
595 Felt252::from(&div_mod(&BigInt::one(), &signature1_s.to_bigint(), &EC_ORDER).unwrap());
596
597 let w2 =
598 Felt252::from(&div_mod(&BigInt::one(), &signature2_s.to_bigint(), &EC_ORDER).unwrap());
599
600 let expected_private_inputs = vec![
601 PrivateInput::Signature(PrivateInputSignature {
602 index: 0,
603 pubkey: pubkey1,
604 msg: msg1,
605 signature_input: SignatureInput {
606 r: signature1_r,
607 w: w1,
608 },
609 }),
610 PrivateInput::Signature(PrivateInputSignature {
611 index: 1,
612 pubkey: pubkey2,
613 msg: msg2,
614 signature_input: SignatureInput {
615 r: signature2_r,
616 w: w2,
617 },
618 }),
619 ];
620
621 let private_inputs = builtin.air_private_input(&segments.memory);
622
623 assert_eq!(private_inputs, expected_private_inputs);
624 }
625}