1use crate::air_private_input::{PrivateInput, PrivateInputPair};
2use crate::types::builtin_name::BuiltinName;
3use crate::types::instance_definitions::pedersen_instance_def::CELLS_PER_HASH;
4use crate::types::relocatable::{MaybeRelocatable, Relocatable};
5use crate::vm::errors::memory_errors::MemoryError;
6use crate::vm::errors::runner_errors::RunnerError;
7use crate::vm::runners::cairo_pie::BuiltinAdditionalData;
8use crate::vm::vm_memory::memory::Memory;
9use crate::vm::vm_memory::memory_segments::MemorySegmentManager;
10use num_integer::{div_ceil, Integer};
11use starknet_types_core::hash::StarkHash;
12use std::cell::RefCell;
13
14#[derive(Debug, Clone)]
15pub struct HashBuiltinRunner {
16 pub base: usize,
17 ratio: Option<u32>,
18 pub(crate) stop_ptr: Option<usize>,
19 pub(crate) included: bool,
20 pub(self) verified_addresses: RefCell<Vec<bool>>,
25}
26
27impl HashBuiltinRunner {
28 pub fn new(ratio: Option<u32>, included: bool) -> Self {
29 HashBuiltinRunner {
30 base: 0,
31 ratio,
32 stop_ptr: None,
33 verified_addresses: RefCell::new(Vec::new()),
34 included,
35 }
36 }
37
38 pub fn initialize_segments(&mut self, segments: &mut MemorySegmentManager) {
39 self.base = segments.add().segment_index as usize }
41
42 pub fn initial_stack(&self) -> Vec<MaybeRelocatable> {
43 if self.included {
44 vec![MaybeRelocatable::from((self.base as isize, 0))]
45 } else {
46 vec![]
47 }
48 }
49
50 pub fn base(&self) -> usize {
51 self.base
52 }
53
54 pub fn ratio(&self) -> Option<u32> {
55 self.ratio
56 }
57
58 pub fn deduce_memory_cell(
59 &self,
60 address: Relocatable,
61 memory: &Memory,
62 ) -> Result<Option<MaybeRelocatable>, RunnerError> {
63 if address.offset.mod_floor(&(CELLS_PER_HASH as usize)) != 2
64 || *self
65 .verified_addresses
66 .borrow()
67 .get(address.offset)
68 .unwrap_or(&false)
69 {
70 return Ok(None);
71 };
72
73 let num_a = memory.get(&MaybeRelocatable::RelocatableValue(Relocatable {
74 segment_index: address.segment_index,
75 offset: address.offset - 1,
76 }));
77 let num_b = memory.get(&MaybeRelocatable::RelocatableValue(Relocatable {
78 segment_index: address.segment_index,
79 offset: address.offset - 2,
80 }));
81 if let (Some(MaybeRelocatable::Int(num_a)), Some(MaybeRelocatable::Int(num_b))) = (
82 num_a.as_ref().map(|x| x.as_ref()),
83 num_b.as_ref().map(|x| x.as_ref()),
84 ) {
85 if self.verified_addresses.borrow().len() <= address.offset {
86 self.verified_addresses
87 .borrow_mut()
88 .resize(address.offset + 1, false);
89 }
90 self.verified_addresses.borrow_mut()[address.offset] = true;
91 let result = starknet_types_core::hash::Pedersen::hash(num_b, num_a);
93 return Ok(Some(MaybeRelocatable::from(result)));
94 }
95 Ok(None)
96 }
97
98 pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result<usize, MemoryError> {
99 segments
100 .get_segment_used_size(self.base())
101 .ok_or(MemoryError::MissingSegmentUsedSizes)
102 }
103
104 pub fn get_used_instances(
105 &self,
106 segments: &MemorySegmentManager,
107 ) -> Result<usize, MemoryError> {
108 let used_cells = self.get_used_cells(segments)?;
109 Ok(div_ceil(used_cells, CELLS_PER_HASH as usize))
110 }
111
112 pub fn get_additional_data(&self) -> BuiltinAdditionalData {
113 let mut verified_addresses = Vec::new();
114 for (offset, is_verified) in self.verified_addresses.borrow().iter().enumerate() {
115 if *is_verified {
116 verified_addresses.push(Relocatable::from((self.base as isize, offset)));
117 }
118 }
119 BuiltinAdditionalData::Hash(verified_addresses)
120 }
121
122 pub fn extend_additional_data(
123 &mut self,
124 additional_data: &BuiltinAdditionalData,
125 ) -> Result<(), RunnerError> {
126 let additional_data = match additional_data {
127 BuiltinAdditionalData::Hash(d) => d,
128 BuiltinAdditionalData::Empty(_) => return Ok(()),
129 _ => return Err(RunnerError::InvalidAdditionalData(BuiltinName::pedersen)),
130 };
131 let mut verified_addresses = self.verified_addresses.borrow_mut();
132 for addr in additional_data {
133 if addr.segment_index != self.base as isize {
134 return Err(RunnerError::InvalidAdditionalData(BuiltinName::pedersen));
135 }
136 if addr.offset > verified_addresses.len() {
138 verified_addresses.resize(addr.offset, false);
139 }
140 verified_addresses.insert(addr.offset, true)
141 }
142 Ok(())
143 }
144
145 pub fn air_private_input(&self, memory: &Memory) -> Vec<PrivateInput> {
146 let mut private_inputs = vec![];
147 if let Some(segment) = memory.data.get(self.base) {
148 let segment_len = segment.len();
149 for (index, off) in (0..segment_len)
150 .step_by(CELLS_PER_HASH as usize)
151 .enumerate()
152 {
153 if let (Ok(x), Ok(y)) = (
155 memory.get_integer((self.base as isize, off).into()),
156 memory.get_integer((self.base as isize, off + 1).into()),
157 ) {
158 private_inputs.push(PrivateInput::Pair(PrivateInputPair {
159 index,
160 x: *x,
161 y: *y,
162 }))
163 }
164 }
165 }
166 private_inputs
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173 use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
174 use crate::types::builtin_name::BuiltinName;
175 use crate::types::program::Program;
176 use crate::utils::test_utils::*;
177 use crate::{felt_hex, relocatable};
178
179 use crate::vm::{errors::memory_errors::MemoryError, runners::builtin_runner::BuiltinRunner};
180
181 #[test]
182 fn get_used_instances() {
183 let builtin = HashBuiltinRunner::new(Some(10), true);
184
185 let mut vm = vm!();
186 vm.segments.segment_used_sizes = Some(vec![1]);
187
188 assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1));
189 }
190
191 #[test]
192 fn final_stack() {
193 let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into();
194
195 let mut vm = vm!();
196
197 vm.segments = segments![
198 ((0, 0), (0, 0)),
199 ((0, 1), (0, 1)),
200 ((2, 0), (0, 0)),
201 ((2, 1), (0, 0))
202 ];
203
204 vm.segments.segment_used_sizes = Some(vec![0]);
205
206 let pointer = Relocatable::from((2, 2));
207
208 assert_eq!(
209 builtin.final_stack(&vm.segments, pointer).unwrap(),
210 Relocatable::from((2, 1))
211 );
212 }
213
214 #[test]
215 fn final_stack_error_stop_pointer() {
216 let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into();
217
218 let mut vm = vm!();
219
220 vm.segments = segments![
221 ((0, 0), (0, 0)),
222 ((0, 1), (0, 1)),
223 ((2, 0), (0, 0)),
224 ((2, 1), (0, 0))
225 ];
226
227 vm.segments.segment_used_sizes = Some(vec![999]);
228
229 let pointer = Relocatable::from((2, 2));
230
231 assert_eq!(
232 builtin.final_stack(&vm.segments, pointer),
233 Err(RunnerError::InvalidStopPointer(Box::new((
234 BuiltinName::pedersen,
235 relocatable!(0, 999),
236 relocatable!(0, 0)
237 ))))
238 );
239 }
240
241 #[test]
242 fn final_stack_error_when_not_included() {
243 let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), false).into();
244
245 let mut vm = vm!();
246
247 vm.segments = segments![
248 ((0, 0), (0, 0)),
249 ((0, 1), (0, 1)),
250 ((2, 0), (0, 0)),
251 ((2, 1), (0, 0))
252 ];
253
254 vm.segments.segment_used_sizes = Some(vec![0]);
255
256 let pointer = Relocatable::from((2, 2));
257
258 assert_eq!(
259 builtin.final_stack(&vm.segments, pointer).unwrap(),
260 Relocatable::from((2, 2))
261 );
262 }
263
264 #[test]
265 fn final_stack_error_non_relocatable() {
266 let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into();
267
268 let mut vm = vm!();
269
270 vm.segments = segments![
271 ((0, 0), (0, 0)),
272 ((0, 1), (0, 1)),
273 ((2, 0), (0, 0)),
274 ((2, 1), 2)
275 ];
276
277 vm.segments.segment_used_sizes = Some(vec![0]);
278
279 let pointer = Relocatable::from((2, 2));
280
281 assert_eq!(
282 builtin.final_stack(&vm.segments, pointer),
283 Err(RunnerError::NoStopPointer(Box::new(BuiltinName::pedersen)))
284 );
285 }
286
287 #[test]
288 fn get_used_cells_and_allocated_size_test() {
289 let builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into();
290
291 let program = program!(
292 builtins = vec![BuiltinName::ec_op],
293 data = vec_data!(
294 (4612671182993129469_i64),
295 (5189976364521848832_i64),
296 (18446744073709551615_i128),
297 (5199546496550207487_i64),
298 (4612389712311386111_i64),
299 (5198983563776393216_i64),
300 (2),
301 (2345108766317314046_i64),
302 (5191102247248822272_i64),
303 (5189976364521848832_i64),
304 (7),
305 (1226245742482522112_i64),
306 ((
307 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
308 10
309 )),
310 (2345108766317314046_i64)
311 ),
312 main = Some(8),
313 );
314
315 let mut cairo_runner = cairo_runner!(program);
316
317 cairo_runner.vm.segments.segment_used_sizes = Some(vec![0]);
318
319 let mut hint_processor = BuiltinHintProcessor::new_empty();
320
321 let address = cairo_runner.initialize(false).unwrap();
322
323 cairo_runner
324 .run_until_pc(address, &mut hint_processor)
325 .unwrap();
326
327 assert_eq!(
328 builtin.get_used_cells_and_allocated_size(&cairo_runner.vm),
329 Ok((0, 3))
330 );
331 }
332
333 #[test]
334 fn get_allocated_memory_units() {
335 let builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into();
336
337 let program = program!(
338 builtins = vec![BuiltinName::ec_op],
339 data = vec_data!(
340 (4612671182993129469_i64),
341 (5189976364521848832_i64),
342 (18446744073709551615_i128),
343 (5199546496550207487_i64),
344 (4612389712311386111_i64),
345 (5198983563776393216_i64),
346 (2),
347 (2345108766317314046_i64),
348 (5191102247248822272_i64),
349 (5189976364521848832_i64),
350 (7),
351 (1226245742482522112_i64),
352 ((
353 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
354 10
355 )),
356 (2345108766317314046_i64)
357 ),
358 main = Some(8),
359 );
360
361 let mut cairo_runner = cairo_runner!(program);
362
363 let mut hint_processor = BuiltinHintProcessor::new_empty();
364
365 let address = cairo_runner.initialize(false).unwrap();
366
367 cairo_runner
368 .run_until_pc(address, &mut hint_processor)
369 .unwrap();
370
371 assert_eq!(builtin.get_allocated_memory_units(&cairo_runner.vm), Ok(3));
372 }
373
374 #[test]
375 fn deduce_memory_cell_pedersen_for_preset_memory_valid() {
376 let memory = memory![((0, 3), 32), ((0, 4), 72), ((0, 5), 0)];
377 let builtin = HashBuiltinRunner::new(Some(8), true);
378
379 let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory);
380 assert_eq!(
381 result,
382 Ok(Some(MaybeRelocatable::from(felt_hex!(
383 "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
384 ))))
385 );
386 assert_eq!(
387 builtin.verified_addresses.into_inner(),
388 vec![false, false, false, false, false, true],
389 );
390 }
391
392 #[test]
393 fn deduce_memory_cell_pedersen_for_preset_memory_incorrect_offset() {
394 let memory = memory![((0, 4), 32), ((0, 5), 72), ((0, 6), 0)];
395 let builtin = HashBuiltinRunner::new(Some(8), true);
396 let result = builtin.deduce_memory_cell(Relocatable::from((0, 6)), &memory);
397 assert_eq!(result, Ok(None));
398 }
399
400 #[test]
401 fn deduce_memory_cell_pedersen_for_preset_memory_no_values_to_hash() {
402 let memory = memory![((0, 4), 72), ((0, 5), 0)];
403 let builtin = HashBuiltinRunner::new(Some(8), true);
404 let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory);
405 assert_eq!(result, Ok(None));
406 }
407
408 #[test]
409 fn deduce_memory_cell_pedersen_for_preset_memory_already_computed() {
410 let memory = memory![((0, 3), 32), ((0, 4), 72), ((0, 5), 0)];
411 let mut builtin = HashBuiltinRunner::new(Some(8), true);
412 builtin.verified_addresses = RefCell::new(vec![false, false, false, false, false, true]);
413 let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory);
414 assert_eq!(result, Ok(None));
415 }
416
417 #[test]
418 fn get_used_cells_missing_segment_used_sizes() {
419 let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(256), true));
420 let vm = vm!();
421
422 assert_eq!(
423 builtin.get_used_cells(&vm.segments),
424 Err(MemoryError::MissingSegmentUsedSizes)
425 );
426 }
427
428 #[test]
429 fn get_used_cells_empty() {
430 let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(256), true));
431 let mut vm = vm!();
432
433 vm.segments.segment_used_sizes = Some(vec![0]);
434 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0));
435 }
436
437 #[test]
438 fn get_used_cells() {
439 let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(256), true));
440 let mut vm = vm!();
441
442 vm.segments.segment_used_sizes = Some(vec![4]);
443 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4));
444 }
445
446 #[test]
447 fn get_additional_data() {
448 let mut builtin = HashBuiltinRunner::new(Some(1), true);
449 let verified_addresses = vec![Relocatable::from((0, 3)), Relocatable::from((0, 6))];
450 builtin.verified_addresses =
451 RefCell::new(vec![false, false, false, true, false, false, true]);
452 assert_eq!(
453 builtin.get_additional_data(),
454 BuiltinAdditionalData::Hash(verified_addresses)
455 )
456 }
457
458 #[test]
459 fn get_and_extend_additional_data() {
460 let mut builtin_a = HashBuiltinRunner::new(Some(1), true);
461 builtin_a.verified_addresses =
462 RefCell::new(vec![false, false, false, true, false, false, true]);
463 let additional_data = builtin_a.get_additional_data();
464 let mut builtin_b = HashBuiltinRunner::new(Some(1), true);
465 builtin_b.extend_additional_data(&additional_data).unwrap();
466 assert_eq!(builtin_a.verified_addresses, builtin_b.verified_addresses);
467 }
468
469 #[test]
470 fn get_air_private_input() {
471 let builtin: BuiltinRunner = HashBuiltinRunner::new(None, true).into();
472
473 let segments = segments![
474 ((0, 0), 0),
475 ((0, 1), 1),
476 ((0, 2), 2),
477 ((0, 3), 3),
478 ((0, 4), 4),
479 ((0, 5), 5),
480 ((0, 6), 6),
481 ((0, 7), 7),
482 ((0, 8), 8),
483 ((0, 9), 9)
484 ];
485 assert_eq!(
486 builtin.air_private_input(&segments),
487 (vec![
488 PrivateInput::Pair(PrivateInputPair {
489 index: 0,
490 x: 0.into(),
491 y: 1.into()
492 }),
493 PrivateInput::Pair(PrivateInputPair {
494 index: 1,
495 x: 3.into(),
496 y: 4.into()
497 }),
498 PrivateInput::Pair(PrivateInputPair {
499 index: 2,
500 x: 6.into(),
501 y: 7.into()
502 }),
503 ]),
504 );
505 }
506}