1use std::collections::BTreeSet;
7
8use crate::native_types::Witness;
9use crate::{AcirField, BlackBoxFunc};
10
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use thiserror::Error;
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
16#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
17pub enum ConstantOrWitnessEnum<F> {
18 Constant(F),
20 Witness(Witness),
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
26#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
27pub struct FunctionInput<F> {
28 input: ConstantOrWitnessEnum<F>,
30 num_bits: u32,
34}
35
36impl<F> FunctionInput<F> {
37 pub fn to_witness(&self) -> Witness {
38 match self.input {
39 ConstantOrWitnessEnum::Constant(_) => unreachable!("ICE - Expected Witness"),
40 ConstantOrWitnessEnum::Witness(witness) => witness,
41 }
42 }
43
44 pub fn input(self) -> ConstantOrWitnessEnum<F> {
45 self.input
46 }
47
48 pub fn input_ref(&self) -> &ConstantOrWitnessEnum<F> {
49 &self.input
50 }
51
52 pub fn num_bits(&self) -> u32 {
53 self.num_bits
54 }
55
56 pub fn witness(witness: Witness, num_bits: u32) -> FunctionInput<F> {
57 FunctionInput { input: ConstantOrWitnessEnum::Witness(witness), num_bits }
58 }
59
60 pub fn is_constant(&self) -> bool {
61 matches!(self.input, ConstantOrWitnessEnum::Constant(_))
62 }
63}
64
65#[derive(Clone, PartialEq, Eq, Debug, Error)]
66#[error("FunctionInput value has too many bits: value: {value}, {value_num_bits} >= {max_bits}")]
67pub struct InvalidInputBitSize {
68 pub value: String,
69 pub value_num_bits: u32,
70 pub max_bits: u32,
71}
72
73impl<F: AcirField> FunctionInput<F> {
74 pub fn constant(value: F, max_bits: u32) -> Result<FunctionInput<F>, InvalidInputBitSize> {
75 if value.num_bits() <= max_bits {
76 Ok(FunctionInput { input: ConstantOrWitnessEnum::Constant(value), num_bits: max_bits })
77 } else {
78 let value_num_bits = value.num_bits();
79 let value = format!("{value}");
80 Err(InvalidInputBitSize { value, value_num_bits, max_bits })
81 }
82 }
83}
84
85impl<F: std::fmt::Display> std::fmt::Display for FunctionInput<F> {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match &self.input {
88 ConstantOrWitnessEnum::Constant(constant) => {
89 write!(f, "({constant}, {})", self.num_bits)
90 }
91 ConstantOrWitnessEnum::Witness(witness) => {
92 write!(f, "({}, {})", witness, self.num_bits)
93 }
94 }
95 }
96}
97
98#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
104pub enum BlackBoxFuncCall<F> {
105 AES128Encrypt {
112 inputs: Vec<FunctionInput<F>>,
113 iv: Box<[FunctionInput<F>; 16]>,
114 key: Box<[FunctionInput<F>; 16]>,
115 outputs: Vec<Witness>,
116 },
117 AND { lhs: FunctionInput<F>, rhs: FunctionInput<F>, output: Witness },
124 XOR { lhs: FunctionInput<F>, rhs: FunctionInput<F>, output: Witness },
131 RANGE { input: FunctionInput<F> },
135 Blake2s { inputs: Vec<FunctionInput<F>>, outputs: Box<[Witness; 32]> },
141 Blake3 { inputs: Vec<FunctionInput<F>>, outputs: Box<[Witness; 32]> },
146 EcdsaSecp256k1 {
168 public_key_x: Box<[FunctionInput<F>; 32]>,
169 public_key_y: Box<[FunctionInput<F>; 32]>,
170 #[serde(
171 serialize_with = "serialize_big_array",
172 deserialize_with = "deserialize_big_array_into_box"
173 )]
174 signature: Box<[FunctionInput<F>; 64]>,
175 hashed_message: Box<[FunctionInput<F>; 32]>,
176 output: Witness,
177 },
178 EcdsaSecp256r1 {
182 public_key_x: Box<[FunctionInput<F>; 32]>,
183 public_key_y: Box<[FunctionInput<F>; 32]>,
184 #[serde(
185 serialize_with = "serialize_big_array",
186 deserialize_with = "deserialize_big_array_into_box"
187 )]
188 signature: Box<[FunctionInput<F>; 64]>,
189 hashed_message: Box<[FunctionInput<F>; 32]>,
190 output: Witness,
191 },
192 MultiScalarMul {
209 points: Vec<FunctionInput<F>>,
210 scalars: Vec<FunctionInput<F>>,
211 outputs: (Witness, Witness, Witness),
212 },
213 EmbeddedCurveAdd {
223 input1: Box<[FunctionInput<F>; 3]>,
224 input2: Box<[FunctionInput<F>; 3]>,
225 outputs: (Witness, Witness, Witness),
226 },
227 Keccakf1600 { inputs: Box<[FunctionInput<F>; 25]>, outputs: Box<[Witness; 25]> },
231 RecursiveAggregation {
254 verification_key: Vec<FunctionInput<F>>,
256 proof: Vec<FunctionInput<F>>,
257 public_inputs: Vec<FunctionInput<F>>,
261 key_hash: FunctionInput<F>,
265 proof_type: u32,
272 },
273 BigIntAdd { lhs: u32, rhs: u32, output: u32 },
275 BigIntSub { lhs: u32, rhs: u32, output: u32 },
277 BigIntMul { lhs: u32, rhs: u32, output: u32 },
279 BigIntDiv { lhs: u32, rhs: u32, output: u32 },
281 BigIntFromLeBytes { inputs: Vec<FunctionInput<F>>, modulus: Vec<u8>, output: u32 },
283 BigIntToLeBytes { input: u32, outputs: Vec<Witness> },
285 Poseidon2Permutation {
288 inputs: Vec<FunctionInput<F>>,
290 outputs: Vec<Witness>,
292 len: u32,
295 },
296 Sha256Compression {
304 inputs: Box<[FunctionInput<F>; 16]>,
306 hash_values: Box<[FunctionInput<F>; 8]>,
308 outputs: Box<[Witness; 8]>,
310 },
311}
312
313impl<F> BlackBoxFuncCall<F> {
314 pub fn get_black_box_func(&self) -> BlackBoxFunc {
315 match self {
316 BlackBoxFuncCall::AES128Encrypt { .. } => BlackBoxFunc::AES128Encrypt,
317 BlackBoxFuncCall::AND { .. } => BlackBoxFunc::AND,
318 BlackBoxFuncCall::XOR { .. } => BlackBoxFunc::XOR,
319 BlackBoxFuncCall::RANGE { .. } => BlackBoxFunc::RANGE,
320 BlackBoxFuncCall::Blake2s { .. } => BlackBoxFunc::Blake2s,
321 BlackBoxFuncCall::Blake3 { .. } => BlackBoxFunc::Blake3,
322 BlackBoxFuncCall::EcdsaSecp256k1 { .. } => BlackBoxFunc::EcdsaSecp256k1,
323 BlackBoxFuncCall::EcdsaSecp256r1 { .. } => BlackBoxFunc::EcdsaSecp256r1,
324 BlackBoxFuncCall::MultiScalarMul { .. } => BlackBoxFunc::MultiScalarMul,
325 BlackBoxFuncCall::EmbeddedCurveAdd { .. } => BlackBoxFunc::EmbeddedCurveAdd,
326 BlackBoxFuncCall::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600,
327 BlackBoxFuncCall::RecursiveAggregation { .. } => BlackBoxFunc::RecursiveAggregation,
328 BlackBoxFuncCall::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd,
329 BlackBoxFuncCall::BigIntSub { .. } => BlackBoxFunc::BigIntSub,
330 BlackBoxFuncCall::BigIntMul { .. } => BlackBoxFunc::BigIntMul,
331 BlackBoxFuncCall::BigIntDiv { .. } => BlackBoxFunc::BigIntDiv,
332 BlackBoxFuncCall::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes,
333 BlackBoxFuncCall::BigIntToLeBytes { .. } => BlackBoxFunc::BigIntToLeBytes,
334 BlackBoxFuncCall::Poseidon2Permutation { .. } => BlackBoxFunc::Poseidon2Permutation,
335 BlackBoxFuncCall::Sha256Compression { .. } => BlackBoxFunc::Sha256Compression,
336 }
337 }
338
339 pub fn name(&self) -> &str {
340 self.get_black_box_func().name()
341 }
342
343 pub fn get_outputs_vec(&self) -> Vec<Witness> {
344 match self {
345 BlackBoxFuncCall::Blake2s { outputs, .. }
346 | BlackBoxFuncCall::Blake3 { outputs, .. } => outputs.to_vec(),
347
348 BlackBoxFuncCall::Keccakf1600 { outputs, .. } => outputs.to_vec(),
349
350 BlackBoxFuncCall::Sha256Compression { outputs, .. } => outputs.to_vec(),
351
352 BlackBoxFuncCall::AES128Encrypt { outputs, .. }
353 | BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } => outputs.to_vec(),
354
355 BlackBoxFuncCall::AND { output, .. }
356 | BlackBoxFuncCall::XOR { output, .. }
357 | BlackBoxFuncCall::EcdsaSecp256k1 { output, .. }
358 | BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } => vec![*output],
359 BlackBoxFuncCall::MultiScalarMul { outputs, .. }
360 | BlackBoxFuncCall::EmbeddedCurveAdd { outputs, .. } => {
361 vec![outputs.0, outputs.1, outputs.2]
362 }
363 BlackBoxFuncCall::RANGE { .. }
364 | BlackBoxFuncCall::RecursiveAggregation { .. }
365 | BlackBoxFuncCall::BigIntFromLeBytes { .. }
366 | BlackBoxFuncCall::BigIntAdd { .. }
367 | BlackBoxFuncCall::BigIntSub { .. }
368 | BlackBoxFuncCall::BigIntMul { .. }
369 | BlackBoxFuncCall::BigIntDiv { .. } => {
370 vec![]
371 }
372 BlackBoxFuncCall::BigIntToLeBytes { outputs, .. } => outputs.to_vec(),
373 }
374 }
375}
376
377impl<F: Copy> BlackBoxFuncCall<F> {
378 pub fn get_inputs_vec(&self) -> Vec<FunctionInput<F>> {
379 match self {
380 BlackBoxFuncCall::Blake2s { inputs, .. }
381 | BlackBoxFuncCall::Blake3 { inputs, .. }
382 | BlackBoxFuncCall::BigIntFromLeBytes { inputs, .. }
383 | BlackBoxFuncCall::Poseidon2Permutation { inputs, .. } => inputs.to_vec(),
384
385 BlackBoxFuncCall::Keccakf1600 { inputs, .. } => inputs.to_vec(),
386 BlackBoxFuncCall::AES128Encrypt { inputs, iv, key, .. } => {
387 let mut all_inputs: Vec<FunctionInput<F>> =
388 Vec::with_capacity(inputs.len() + iv.len() + key.len());
389 all_inputs.extend(**iv);
390 all_inputs.extend(**key);
391 all_inputs
392 }
393 BlackBoxFuncCall::Sha256Compression { inputs, hash_values, .. } => {
394 inputs.iter().chain(hash_values.as_ref()).copied().collect()
395 }
396 BlackBoxFuncCall::AND { lhs, rhs, .. } | BlackBoxFuncCall::XOR { lhs, rhs, .. } => {
397 vec![*lhs, *rhs]
398 }
399 BlackBoxFuncCall::BigIntAdd { .. }
400 | BlackBoxFuncCall::BigIntSub { .. }
401 | BlackBoxFuncCall::BigIntMul { .. }
402 | BlackBoxFuncCall::BigIntDiv { .. }
403 | BlackBoxFuncCall::BigIntToLeBytes { .. } => Vec::new(),
404 BlackBoxFuncCall::MultiScalarMul { points, scalars, .. } => {
405 let mut inputs: Vec<FunctionInput<F>> =
406 Vec::with_capacity(points.len() + scalars.len());
407 inputs.extend(points.iter().copied());
408 inputs.extend(scalars.iter().copied());
409 inputs
410 }
411 BlackBoxFuncCall::EmbeddedCurveAdd { input1, input2, .. } => {
412 vec![input1[0], input1[1], input1[2], input2[0], input2[1], input2[2]]
413 }
414 BlackBoxFuncCall::RANGE { input } => vec![*input],
415 BlackBoxFuncCall::EcdsaSecp256k1 {
416 public_key_x,
417 public_key_y,
418 signature,
419 hashed_message,
420 ..
421 } => {
422 let mut inputs = Vec::with_capacity(
423 public_key_x.len()
424 + public_key_y.len()
425 + signature.len()
426 + hashed_message.len(),
427 );
428 inputs.extend(public_key_x.iter().copied());
429 inputs.extend(public_key_y.iter().copied());
430 inputs.extend(signature.iter().copied());
431 inputs.extend(hashed_message.iter().copied());
432 inputs
433 }
434 BlackBoxFuncCall::EcdsaSecp256r1 {
435 public_key_x,
436 public_key_y,
437 signature,
438 hashed_message,
439 ..
440 } => {
441 let mut inputs = Vec::with_capacity(
442 public_key_x.len()
443 + public_key_y.len()
444 + signature.len()
445 + hashed_message.len(),
446 );
447 inputs.extend(public_key_x.iter().copied());
448 inputs.extend(public_key_y.iter().copied());
449 inputs.extend(signature.iter().copied());
450 inputs.extend(hashed_message.iter().copied());
451 inputs
452 }
453 BlackBoxFuncCall::RecursiveAggregation {
454 verification_key: key,
455 proof,
456 public_inputs,
457 key_hash,
458 proof_type: _,
459 } => {
460 let mut inputs = Vec::new();
461 inputs.extend(key.iter().copied());
462 inputs.extend(proof.iter().copied());
463 inputs.extend(public_inputs.iter().copied());
464 inputs.push(*key_hash);
465 inputs
466 }
467 }
468 }
469
470 pub fn get_input_witnesses(&self) -> BTreeSet<Witness> {
471 let mut result = BTreeSet::new();
472 for input in self.get_inputs_vec() {
473 if let ConstantOrWitnessEnum::Witness(w) = input.input() {
474 result.insert(w);
475 }
476 }
477 result
478 }
479}
480
481impl<F: std::fmt::Display + Copy> std::fmt::Display for BlackBoxFuncCall<F> {
482 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
483 let uppercase_name = self.name().to_uppercase();
484 write!(f, "BLACKBOX::{uppercase_name} ")?;
485 let inputs_str = &self
488 .get_inputs_vec()
489 .iter()
490 .map(|i| i.to_string())
491 .collect::<Vec<String>>()
492 .join(", ");
493
494 write!(f, "[{inputs_str}]")?;
495
496 write!(f, " ")?;
497
498 let outputs_str = &self
501 .get_outputs_vec()
502 .iter()
503 .map(|i| format!("_{}", i.0))
504 .collect::<Vec<String>>()
505 .join(", ");
506
507 write!(f, "[{outputs_str}]")
508 }
509}
510
511impl<F: std::fmt::Display + Copy> std::fmt::Debug for BlackBoxFuncCall<F> {
512 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
513 std::fmt::Display::fmt(self, f)
514 }
515}
516
517fn serialize_big_array<S, F: Serialize>(
518 big_array: &[FunctionInput<F>; 64],
519 s: S,
520) -> Result<S::Ok, S::Error>
521where
522 S: Serializer,
523{
524 use serde_big_array::BigArray;
525
526 (*big_array).serialize(s)
527}
528
529fn deserialize_big_array_into_box<'de, D, F: Deserialize<'de>>(
530 deserializer: D,
531) -> Result<Box<[FunctionInput<F>; 64]>, D::Error>
532where
533 D: Deserializer<'de>,
534{
535 use serde_big_array::BigArray;
536
537 let big_array: [FunctionInput<F>; 64] = BigArray::deserialize(deserializer)?;
538 Ok(Box::new(big_array))
539}
540
541#[cfg(test)]
542mod tests {
543
544 use crate::{circuit::Opcode, native_types::Witness};
545 use acir_field::{AcirField, FieldElement};
546
547 use super::{BlackBoxFuncCall, FunctionInput};
548
549 fn keccakf1600_opcode<F: AcirField>() -> Opcode<F> {
550 let inputs: Box<[FunctionInput<F>; 25]> =
551 Box::new(std::array::from_fn(|i| FunctionInput::witness(Witness(i as u32 + 1), 8)));
552 let outputs: Box<[Witness; 25]> = Box::new(std::array::from_fn(|i| Witness(i as u32 + 26)));
553
554 Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Keccakf1600 { inputs, outputs })
555 }
556
557 #[test]
558 fn keccakf1600_serialization_roundtrip() {
559 use crate::serialization::{bincode_deserialize, bincode_serialize};
560
561 let opcode = keccakf1600_opcode::<FieldElement>();
562 let buf = bincode_serialize(&opcode).unwrap();
563 let recovered_opcode = bincode_deserialize(&buf).unwrap();
564 assert_eq!(opcode, recovered_opcode);
565 }
566}
567
568#[cfg(feature = "arb")]
569mod arb {
570 use acir_field::AcirField;
571 use proptest::prelude::*;
572
573 use crate::native_types::Witness;
574
575 use super::{BlackBoxFuncCall, FunctionInput};
576
577 impl<F> Arbitrary for BlackBoxFuncCall<F>
579 where
580 F: AcirField + Arbitrary,
581 {
582 type Parameters = ();
583 type Strategy = BoxedStrategy<Self>;
584
585 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
586 let input = any::<FunctionInput<F>>();
587 let input_vec = any::<Vec<FunctionInput<F>>>();
588 let input_arr_3 = any::<Box<[FunctionInput<F>; 3]>>();
589 let input_arr_8 = any::<Box<[FunctionInput<F>; 8]>>();
590 let input_arr_16 = any::<Box<[FunctionInput<F>; 16]>>();
591 let input_arr_25 = any::<Box<[FunctionInput<F>; 25]>>();
592 let input_arr_32 = any::<Box<[FunctionInput<F>; 32]>>();
593 let input_arr_64 = any::<Box<[FunctionInput<F>; 64]>>();
594 let witness = any::<Witness>();
595 let witness_vec = any::<Vec<Witness>>();
596 let witness_arr_8 = any::<Box<[Witness; 8]>>();
597 let witness_arr_25 = any::<Box<[Witness; 25]>>();
598 let witness_arr_32 = any::<Box<[Witness; 32]>>();
599
600 let case_aes128_encrypt = (
601 input_vec.clone(),
602 input_arr_16.clone(),
603 input_arr_16.clone(),
604 witness_vec.clone(),
605 )
606 .prop_map(|(inputs, iv, key, outputs)| {
607 BlackBoxFuncCall::AES128Encrypt { inputs, iv, key, outputs }
608 });
609
610 let case_and = (input.clone(), input.clone(), witness.clone())
611 .prop_map(|(lhs, rhs, output)| BlackBoxFuncCall::AND { lhs, rhs, output });
612
613 let case_xor = (input.clone(), input.clone(), witness.clone())
614 .prop_map(|(lhs, rhs, output)| BlackBoxFuncCall::XOR { lhs, rhs, output });
615
616 let case_range = input.clone().prop_map(|input| BlackBoxFuncCall::RANGE { input });
617
618 let case_blake2s = (input_vec.clone(), witness_arr_32.clone())
619 .prop_map(|(inputs, outputs)| BlackBoxFuncCall::Blake2s { inputs, outputs });
620
621 let case_blake3 = (input_vec.clone(), witness_arr_32.clone())
622 .prop_map(|(inputs, outputs)| BlackBoxFuncCall::Blake3 { inputs, outputs });
623
624 let case_ecdsa_secp256k1 = (
625 input_arr_32.clone(),
626 input_arr_32.clone(),
627 input_arr_64.clone(),
628 input_arr_32.clone(),
629 witness.clone(),
630 )
631 .prop_map(
632 |(public_key_x, public_key_y, signature, hashed_message, output)| {
633 BlackBoxFuncCall::EcdsaSecp256k1 {
634 public_key_x,
635 public_key_y,
636 signature,
637 hashed_message,
638 output,
639 }
640 },
641 );
642
643 let case_ecdsa_secp256r1 = (
644 input_arr_32.clone(),
645 input_arr_32.clone(),
646 input_arr_64.clone(),
647 input_arr_32.clone(),
648 witness.clone(),
649 )
650 .prop_map(
651 |(public_key_x, public_key_y, signature, hashed_message, output)| {
652 BlackBoxFuncCall::EcdsaSecp256r1 {
653 public_key_x,
654 public_key_y,
655 signature,
656 hashed_message,
657 output,
658 }
659 },
660 );
661
662 let case_multi_scalar_mul = (
663 input_vec.clone(),
664 input_vec.clone(),
665 witness.clone(),
666 witness.clone(),
667 witness.clone(),
668 )
669 .prop_map(|(points, scalars, w1, w2, w3)| {
670 BlackBoxFuncCall::MultiScalarMul { points, scalars, outputs: (w1, w2, w3) }
671 });
672
673 let case_embedded_curve_add = (
674 input_arr_3.clone(),
675 input_arr_3.clone(),
676 witness.clone(),
677 witness.clone(),
678 witness.clone(),
679 )
680 .prop_map(|(input1, input2, w1, w2, w3)| {
681 BlackBoxFuncCall::EmbeddedCurveAdd { input1, input2, outputs: (w1, w2, w3) }
682 });
683
684 let case_keccakf1600 = (input_arr_25.clone(), witness_arr_25.clone())
685 .prop_map(|(inputs, outputs)| BlackBoxFuncCall::Keccakf1600 { inputs, outputs });
686
687 let case_recursive_aggregation = (
688 input_vec.clone(),
689 input_vec.clone(),
690 input_vec.clone(),
691 input.clone(),
692 any::<u32>(),
693 )
694 .prop_map(
695 |(verification_key, proof, public_inputs, key_hash, proof_type)| {
696 BlackBoxFuncCall::RecursiveAggregation {
697 verification_key,
698 proof,
699 public_inputs,
700 key_hash,
701 proof_type,
702 }
703 },
704 );
705
706 let big_int_args = (any::<u32>(), any::<u32>(), any::<u32>());
707
708 let case_big_int_add = big_int_args
709 .prop_map(|(lhs, rhs, output)| BlackBoxFuncCall::BigIntAdd { lhs, rhs, output });
710
711 let case_big_int_sub = big_int_args
712 .prop_map(|(lhs, rhs, output)| BlackBoxFuncCall::BigIntSub { lhs, rhs, output });
713
714 let case_big_int_mul = big_int_args
715 .prop_map(|(lhs, rhs, output)| BlackBoxFuncCall::BigIntMul { lhs, rhs, output });
716
717 let case_big_int_div = big_int_args
718 .prop_map(|(lhs, rhs, output)| BlackBoxFuncCall::BigIntDiv { lhs, rhs, output });
719
720 let case_big_int_from_le_bytes = (input_vec.clone(), any::<Vec<u8>>(), any::<u32>())
721 .prop_map(|(inputs, modulus, output)| BlackBoxFuncCall::BigIntFromLeBytes {
722 inputs,
723 modulus,
724 output,
725 });
726
727 let case_big_int_to_le_bytes = (any::<u32>(), witness_vec.clone())
728 .prop_map(|(input, outputs)| BlackBoxFuncCall::BigIntToLeBytes { input, outputs });
729
730 let case_poseidon2_permutation = (input_vec.clone(), witness_vec.clone(), any::<u32>())
731 .prop_map(|(inputs, outputs, len)| BlackBoxFuncCall::Poseidon2Permutation {
732 inputs,
733 outputs,
734 len,
735 });
736
737 let case_sha256_compression = (input_arr_16, input_arr_8, witness_arr_8).prop_map(
738 |(inputs, hash_values, outputs)| BlackBoxFuncCall::Sha256Compression {
739 inputs,
740 hash_values,
741 outputs,
742 },
743 );
744
745 prop_oneof![
746 case_aes128_encrypt,
747 case_and,
748 case_xor,
749 case_range,
750 case_blake2s,
751 case_blake3,
752 case_ecdsa_secp256k1,
753 case_ecdsa_secp256r1,
754 case_multi_scalar_mul,
755 case_embedded_curve_add,
756 case_keccakf1600,
757 case_recursive_aggregation,
758 case_big_int_add,
759 case_big_int_sub,
760 case_big_int_mul,
761 case_big_int_div,
762 case_big_int_from_le_bytes,
763 case_big_int_to_le_bytes,
764 case_poseidon2_permutation,
765 case_sha256_compression,
766 ]
767 .boxed()
768 }
769 }
770}