1use crate::air_private_input::{PrivateInput, PrivateInputPair};
2use crate::stdlib::{boxed::Box, vec::Vec};
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 #[cfg(target_arch = "wasm32")]
181 use wasm_bindgen_test::*;
182
183 #[test]
184 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
185 fn get_used_instances() {
186 let builtin = BitwiseBuiltinRunner::new(Some(10), true);
187 let mut vm = vm!();
188
189 vm.segments = segments![
190 ((0, 0), (0, 0)),
191 ((0, 1), (0, 1)),
192 ((2, 0), (0, 0)),
193 ((2, 1), (0, 0))
194 ];
195
196 vm.segments.segment_used_sizes = Some(vec![1]);
197
198 assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1));
199 }
200
201 #[test]
202 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
203 fn final_stack() {
204 let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into();
205 let mut vm = vm!();
206
207 vm.segments = segments![
208 ((0, 0), (0, 0)),
209 ((0, 1), (0, 1)),
210 ((2, 0), (0, 0)),
211 ((2, 1), (0, 0))
212 ];
213
214 vm.segments.segment_used_sizes = Some(vec![0]);
215
216 let pointer = Relocatable::from((2, 2));
217
218 assert_eq!(
219 builtin.final_stack(&vm.segments, pointer).unwrap(),
220 Relocatable::from((2, 1))
221 );
222 }
223
224 #[test]
225 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
226 fn final_stack_error_stop_pointer() {
227 let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into();
228 let mut vm = vm!();
229
230 vm.segments = segments![
231 ((0, 0), (0, 0)),
232 ((0, 1), (0, 1)),
233 ((2, 0), (0, 0)),
234 ((2, 1), (0, 0))
235 ];
236
237 vm.segments.segment_used_sizes = Some(vec![995]);
238
239 let pointer = Relocatable::from((2, 2));
240
241 assert_eq!(
242 builtin.final_stack(&vm.segments, pointer),
243 Err(RunnerError::InvalidStopPointer(Box::new((
244 BuiltinName::bitwise,
245 relocatable!(0, 995),
246 relocatable!(0, 0)
247 ))))
248 );
249 }
250
251 #[test]
252 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
253 fn final_stack_error_when_notincluded() {
254 let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), false).into();
255 let mut vm = vm!();
256
257 vm.segments = segments![
258 ((0, 0), (0, 0)),
259 ((0, 1), (0, 1)),
260 ((2, 0), (0, 0)),
261 ((2, 1), (0, 0))
262 ];
263
264 vm.segments.segment_used_sizes = Some(vec![0]);
265
266 let pointer = Relocatable::from((2, 2));
267
268 assert_eq!(
269 builtin.final_stack(&vm.segments, pointer).unwrap(),
270 Relocatable::from((2, 2))
271 );
272 }
273
274 #[test]
275 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
276 fn final_stack_error_non_relocatable() {
277 let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into();
278 let mut vm = vm!();
279
280 vm.segments = segments![
281 ((0, 0), (0, 0)),
282 ((0, 1), (0, 1)),
283 ((2, 0), (0, 0)),
284 ((2, 1), 2)
285 ];
286
287 vm.segments.segment_used_sizes = Some(vec![0]);
288
289 let pointer = Relocatable::from((2, 2));
290
291 assert_eq!(
292 builtin.final_stack(&vm.segments, pointer),
293 Err(RunnerError::NoStopPointer(Box::new(BuiltinName::bitwise)))
294 );
295 }
296
297 #[test]
298 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
299 fn get_used_cells_and_allocated_size_test() {
300 let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into();
301
302 let program = program!(
303 builtins = vec![BuiltinName::bitwise],
304 data = vec_data!(
305 (4612671182993129469_i64),
306 (5189976364521848832_i64),
307 (18446744073709551615_i128),
308 (5199546496550207487_i64),
309 (4612389712311386111_i64),
310 (5198983563776393216_i64),
311 (2),
312 (2345108766317314046_i64),
313 (5191102247248822272_i64),
314 (5189976364521848832_i64),
315 (7),
316 (1226245742482522112_i64),
317 ((
318 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
319 10
320 )),
321 (2345108766317314046_i64)
322 ),
323 main = Some(8),
324 );
325
326 let mut cairo_runner = cairo_runner!(program);
327 cairo_runner.vm.segments.segment_used_sizes = Some(vec![0]);
328
329 let mut hint_processor = BuiltinHintProcessor::new_empty();
330
331 let address = cairo_runner.initialize(false).unwrap();
332
333 cairo_runner
334 .run_until_pc(address, &mut hint_processor)
335 .unwrap();
336
337 assert_eq!(
338 builtin.get_used_cells_and_allocated_size(&cairo_runner.vm),
339 Ok((0, 5))
340 );
341 }
342
343 #[test]
344 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
345 fn get_allocated_memory_units() {
346 let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into();
347
348 let program = program!(
349 builtins = vec![BuiltinName::pedersen, BuiltinName::bitwise],
350 data = vec_data!(
351 (4612671182993129469_i64),
352 (5189976364521848832_i64),
353 (18446744073709551615_i128),
354 (5199546496550207487_i64),
355 (4612389712311386111_i64),
356 (5198983563776393216_i64),
357 (2),
358 (2345108766317314046_i64),
359 (5191102247248822272_i64),
360 (5189976364521848832_i64),
361 (7),
362 (1226245742482522112_i64),
363 ((
364 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
365 10
366 )),
367 (2345108766317314046_i64)
368 ),
369 main = Some(8),
370 );
371
372 let mut cairo_runner = cairo_runner!(program);
373
374 let mut hint_processor = BuiltinHintProcessor::new_empty();
375
376 let address = cairo_runner.initialize(false).unwrap();
377
378 cairo_runner
379 .run_until_pc(address, &mut hint_processor)
380 .unwrap();
381
382 assert_eq!(builtin.get_allocated_memory_units(&cairo_runner.vm), Ok(5));
383 }
384
385 #[test]
386 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
387 fn deduce_memory_cell_bitwise_for_preset_memory_valid_and() {
388 let memory = memory![((0, 5), 10), ((0, 6), 12), ((0, 7), 0)];
389 let builtin = BitwiseBuiltinRunner::new(Some(256), true);
390 let result = builtin.deduce_memory_cell(Relocatable::from((0, 7)), &memory);
391 assert_eq!(result, Ok(Some(MaybeRelocatable::from(Felt252::from(8)))));
392 }
393
394 #[test]
395 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
396 fn deduce_memory_cell_bitwise_for_preset_memory_valid_xor() {
397 let memory = memory![((0, 5), 10), ((0, 6), 12), ((0, 8), 0)];
398 let builtin = BitwiseBuiltinRunner::new(Some(256), true);
399 let result = builtin.deduce_memory_cell(Relocatable::from((0, 8)), &memory);
400 assert_eq!(result, Ok(Some(MaybeRelocatable::from(Felt252::from(6)))));
401 }
402
403 #[test]
404 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
405 fn deduce_memory_cell_bitwise_for_preset_memory_valid_or() {
406 let memory = memory![((0, 5), 10), ((0, 6), 12), ((0, 9), 0)];
407 let builtin = BitwiseBuiltinRunner::new(Some(256), true);
408 let result = builtin.deduce_memory_cell(Relocatable::from((0, 9)), &memory);
409 assert_eq!(result, Ok(Some(MaybeRelocatable::from(Felt252::from(14)))));
410 }
411
412 #[test]
413 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
414 fn deduce_memory_cell_bitwise_for_preset_memory_incorrect_offset() {
415 let memory = memory![((0, 3), 10), ((0, 4), 12), ((0, 5), 0)];
416 let builtin = BitwiseBuiltinRunner::new(Some(256), true);
417 let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory);
418 assert_eq!(result, Ok(None));
419 }
420
421 #[test]
422 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
423 fn deduce_memory_cell_bitwise_for_preset_memory_no_values_to_operate() {
424 let memory = memory![((0, 5), 12), ((0, 7), 0)];
425 let builtin = BitwiseBuiltinRunner::new(Some(256), true);
426 let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory);
427 assert_eq!(result, Ok(None));
428 }
429
430 #[test]
431 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
432 fn get_used_cells_missing_segment_used_sizes() {
433 let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
434 let vm = vm!();
435
436 assert_eq!(
437 builtin.get_used_cells(&vm.segments),
438 Err(MemoryError::MissingSegmentUsedSizes)
439 );
440 }
441
442 #[test]
443 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
444 fn get_used_cells_empty() {
445 let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
446 let mut vm = vm!();
447
448 vm.segments.segment_used_sizes = Some(vec![0]);
449 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0));
450 }
451
452 #[test]
453 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
454 fn get_used_cells() {
455 let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
456 let mut vm = vm!();
457
458 vm.segments.segment_used_sizes = Some(vec![4]);
459 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4));
460 }
461
462 #[test]
463 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
464 fn get_used_diluted_check_units_a() {
465 let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
466 assert_eq!(builtin.get_used_diluted_check_units(12, 2), 535);
467 }
468
469 #[test]
470 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
471 fn get_used_diluted_check_units_b() {
472 let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
473 assert_eq!(builtin.get_used_diluted_check_units(30, 56), 150);
474 }
475
476 #[test]
477 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
478 fn get_used_diluted_check_units_c() {
479 let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
480 assert_eq!(builtin.get_used_diluted_check_units(50, 25), 250);
481 }
482
483 #[test]
484 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
485 fn get_air_private_input() {
486 let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into();
487
488 let segments = segments![
489 ((0, 0), 0),
490 ((0, 1), 1),
491 ((0, 2), 2),
492 ((0, 3), 3),
493 ((0, 4), 4),
494 ((0, 5), 5),
495 ((0, 6), 6),
496 ((0, 7), 7),
497 ((0, 8), 8),
498 ((0, 9), 9),
499 ((0, 10), 10),
500 ((0, 11), 11),
501 ((0, 12), 12),
502 ((0, 13), 13),
503 ((0, 14), 14)
504 ];
505 assert_eq!(
506 builtin.air_private_input(&segments),
507 (vec![
508 PrivateInput::Pair(PrivateInputPair {
509 index: 0,
510 x: 0.into(),
511 y: 1.into()
512 }),
513 PrivateInput::Pair(PrivateInputPair {
514 index: 1,
515 x: 5.into(),
516 y: 6.into()
517 }),
518 PrivateInput::Pair(PrivateInputPair {
519 index: 2,
520 x: 10.into(),
521 y: 11.into()
522 }),
523 ]),
524 );
525 }
526}