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