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