1use crate::{
2 black_box::BlackBoxOp,
3 lengths::{ElementsFlattenedLength, FlattenedLength, SemanticLength, SemiFlattenedLength},
4};
5use acir_field::AcirField;
6use itertools::Itertools;
7use msgpack_tagged::MsgpackTagged;
8use serde::{Deserialize, Serialize};
9
10pub type Label = usize;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[derive(Serialize, Deserialize, MsgpackTagged)]
17#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
18pub enum MemoryAddress {
19 #[tag(0)]
21 Direct(u32),
22 #[tag(1)]
29 Relative(u32),
30}
31
32impl MemoryAddress {
33 pub fn direct(address: u32) -> Self {
35 MemoryAddress::Direct(address)
36 }
37
38 pub fn relative(offset: u32) -> Self {
40 MemoryAddress::Relative(offset)
41 }
42
43 pub fn unwrap_direct(self) -> u32 {
47 match self {
48 MemoryAddress::Direct(address) => address,
49 MemoryAddress::Relative(_) => panic!("Expected direct memory address"),
50 }
51 }
52
53 pub fn unwrap_relative(self) -> u32 {
57 match self {
58 MemoryAddress::Direct(_) => panic!("Expected relative memory address"),
59 MemoryAddress::Relative(offset) => offset,
60 }
61 }
62
63 pub fn to_u32(self) -> u32 {
65 match self {
66 MemoryAddress::Direct(address) => address,
67 MemoryAddress::Relative(offset) => offset,
68 }
69 }
70
71 pub fn is_relative(&self) -> bool {
72 match self {
73 MemoryAddress::Relative(_) => true,
74 MemoryAddress::Direct(_) => false,
75 }
76 }
77
78 pub fn is_direct(&self) -> bool {
79 !self.is_relative()
80 }
81
82 pub fn offset(&self, amount: u32) -> Self {
86 let address = self.unwrap_direct();
88 MemoryAddress::direct(address.checked_add(amount).expect("memory offset overflow"))
89 }
90}
91
92impl std::fmt::Display for MemoryAddress {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 match self {
95 MemoryAddress::Direct(address) => write!(f, "@{address}"),
96 MemoryAddress::Relative(offset) => write!(f, "sp[{offset}]"),
97 }
98 }
99}
100
101#[derive(Debug, Clone, Eq, PartialEq, Hash)]
103#[derive(Serialize, Deserialize, MsgpackTagged)]
104pub enum HeapValueType {
105 #[tag(0)]
107 Simple(BitSize),
108 #[tag(1)]
112 Array {
113 #[tag(0)]
114 value_types: Vec<HeapValueType>,
115 #[tag(1)]
116 size: SemanticLength,
117 },
118 #[tag(2)]
122 Vector {
123 #[tag(0)]
124 value_types: Vec<HeapValueType>,
125 },
126}
127
128impl HeapValueType {
129 pub fn all_simple(types: &[HeapValueType]) -> bool {
131 types.iter().all(|typ| matches!(typ, HeapValueType::Simple(_)))
132 }
133
134 pub fn field() -> HeapValueType {
136 HeapValueType::Simple(BitSize::Field)
137 }
138
139 pub fn flattened_size(&self) -> Option<FlattenedLength> {
143 match self {
144 HeapValueType::Simple(_) => Some(FlattenedLength(1)),
145 HeapValueType::Array { value_types, size } => {
146 let elements_flattened_size =
148 value_types.iter().map(|t| t.flattened_size()).sum::<Option<FlattenedLength>>();
149 elements_flattened_size.map(|elements_flattened_size| {
151 ElementsFlattenedLength::from(elements_flattened_size) * *size
152 })
153 }
154 HeapValueType::Vector { .. } => {
155 None
157 }
158 }
159 }
160}
161
162impl std::fmt::Display for HeapValueType {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 let write_types =
165 |f: &mut std::fmt::Formatter<'_>, value_types: &[HeapValueType]| -> std::fmt::Result {
166 if value_types.len() == 1 {
167 write!(f, "{}", value_types[0])?;
168 } else {
169 write!(f, "(")?;
170 for (index, value_type) in value_types.iter().enumerate() {
171 if index > 0 {
172 write!(f, ", ")?;
173 }
174 write!(f, "{value_type}")?;
175 }
176 write!(f, ")")?;
177 }
178 Ok(())
179 };
180
181 match self {
182 HeapValueType::Simple(bit_size) => {
183 write!(f, "{bit_size}")
184 }
185 HeapValueType::Array { value_types, size } => {
186 write!(f, "[")?;
187 write_types(f, value_types)?;
188 write!(f, "; {size}")?;
189 write!(f, "]")
190 }
191 HeapValueType::Vector { value_types } => {
192 write!(f, "@[")?;
193 write_types(f, value_types)?;
194 write!(f, "]")
195 }
196 }
197 }
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
202#[derive(Serialize, Deserialize, MsgpackTagged)]
203#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
204pub struct HeapArray {
205 #[tag(0)]
209 pub pointer: MemoryAddress,
210 #[tag(1)]
212 pub size: SemiFlattenedLength,
213}
214
215impl Default for HeapArray {
216 fn default() -> Self {
217 Self { pointer: MemoryAddress::direct(0), size: SemiFlattenedLength(0) }
218 }
219}
220
221impl std::fmt::Display for HeapArray {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 write!(f, "[{}; {}]", self.pointer, self.size)
224 }
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
229#[derive(Serialize, Deserialize, MsgpackTagged)]
230#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
231pub struct HeapVector {
232 #[tag(0)]
236 pub pointer: MemoryAddress,
237 #[tag(1)]
239 pub size: MemoryAddress,
240}
241
242impl std::fmt::Display for HeapVector {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 write!(f, "@[{}; {}]", self.pointer, self.size)
245 }
246}
247
248#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, Hash)]
252#[derive(Serialize, Deserialize, MsgpackTagged)]
253#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
254pub enum IntegerBitSize {
255 #[tag(0)]
256 U1,
257 #[tag(1)]
258 U8,
259 #[tag(2)]
260 U16,
261 #[tag(3)]
262 U32,
263 #[tag(4)]
264 U64,
265 #[tag(5)]
266 U128,
267}
268
269impl IntegerBitSize {
270 pub const fn to_u32(self) -> u32 {
271 match self {
272 IntegerBitSize::U1 => 1,
273 IntegerBitSize::U8 => 8,
274 IntegerBitSize::U16 => 16,
275 IntegerBitSize::U32 => 32,
276 IntegerBitSize::U64 => 64,
277 IntegerBitSize::U128 => 128,
278 }
279 }
280}
281
282impl From<IntegerBitSize> for u32 {
283 fn from(bit_size: IntegerBitSize) -> u32 {
284 bit_size.to_u32()
285 }
286}
287
288impl TryFrom<u32> for IntegerBitSize {
289 type Error = &'static str;
290
291 fn try_from(value: u32) -> Result<Self, Self::Error> {
292 match value {
293 1 => Ok(IntegerBitSize::U1),
294 8 => Ok(IntegerBitSize::U8),
295 16 => Ok(IntegerBitSize::U16),
296 32 => Ok(IntegerBitSize::U32),
297 64 => Ok(IntegerBitSize::U64),
298 128 => Ok(IntegerBitSize::U128),
299 _ => Err("Invalid bit size"),
300 }
301 }
302}
303
304impl std::fmt::Display for IntegerBitSize {
305 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
306 match self {
307 IntegerBitSize::U1 => write!(f, "bool"),
308 IntegerBitSize::U8 => write!(f, "u8"),
309 IntegerBitSize::U16 => write!(f, "u16"),
310 IntegerBitSize::U32 => write!(f, "u32"),
311 IntegerBitSize::U64 => write!(f, "u64"),
312 IntegerBitSize::U128 => write!(f, "u128"),
313 }
314 }
315}
316
317#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, Hash)]
322#[derive(Serialize, Deserialize, MsgpackTagged)]
323#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
324pub enum BitSize {
325 #[tag(0)]
326 Field,
327 #[tag(1)]
328 Integer(IntegerBitSize),
329}
330
331impl BitSize {
332 pub fn to_u32<F: AcirField>(self) -> u32 {
337 match self {
338 BitSize::Field => F::max_num_bits(),
339 BitSize::Integer(bit_size) => bit_size.into(),
340 }
341 }
342
343 pub fn try_from_u32<F: AcirField>(value: u32) -> Result<Self, &'static str> {
348 if value == F::max_num_bits() {
349 Ok(BitSize::Field)
350 } else {
351 Ok(BitSize::Integer(IntegerBitSize::try_from(value)?))
352 }
353 }
354}
355
356impl std::fmt::Display for BitSize {
357 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
358 match self {
359 BitSize::Field => write!(f, "field"),
360 BitSize::Integer(bit_size) => write!(f, "{bit_size}"),
361 }
362 }
363}
364
365#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
372#[derive(Serialize, Deserialize, MsgpackTagged)]
373#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
374pub enum ValueOrArray {
375 #[tag(0)]
380 MemoryAddress(MemoryAddress),
381 #[tag(1)]
385 HeapArray(HeapArray),
386 #[tag(2)]
390 HeapVector(HeapVector),
391}
392
393impl std::fmt::Display for ValueOrArray {
394 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
395 match self {
396 ValueOrArray::MemoryAddress(memory_address) => {
397 write!(f, "{memory_address}")
398 }
399 ValueOrArray::HeapArray(heap_array) => {
400 write!(f, "{heap_array}")
401 }
402 ValueOrArray::HeapVector(heap_vector) => {
403 write!(f, "{heap_vector}")
404 }
405 }
406 }
407}
408
409#[derive(Debug, Clone, PartialEq, Eq, Hash)]
410#[derive(Serialize, Deserialize, MsgpackTagged)]
411#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
412pub enum BrilligOpcode<F> {
413 #[tag(0)]
417 BinaryFieldOp {
418 #[tag(0)]
419 destination: MemoryAddress,
420 #[tag(1)]
421 op: BinaryFieldOp,
422 #[tag(2)]
423 lhs: MemoryAddress,
424 #[tag(3)]
425 rhs: MemoryAddress,
426 },
427 #[tag(1)]
431 BinaryIntOp {
432 #[tag(0)]
433 destination: MemoryAddress,
434 #[tag(1)]
435 op: BinaryIntOp,
436 #[tag(2)]
437 bit_size: IntegerBitSize,
438 #[tag(3)]
439 lhs: MemoryAddress,
440 #[tag(4)]
441 rhs: MemoryAddress,
442 },
443 #[tag(2)]
446 Not {
447 #[tag(0)]
448 destination: MemoryAddress,
449 #[tag(1)]
450 source: MemoryAddress,
451 #[tag(2)]
452 bit_size: IntegerBitSize,
453 },
454 #[tag(3)]
458 Cast {
459 #[tag(0)]
460 destination: MemoryAddress,
461 #[tag(1)]
462 source: MemoryAddress,
463 #[tag(2)]
464 bit_size: BitSize,
465 },
466 #[tag(4)]
469 JumpIf {
470 #[tag(0)]
471 condition: MemoryAddress,
472 #[tag(1)]
473 location: Label,
474 },
475 #[tag(5)]
477 Jump {
478 #[tag(0)]
479 location: Label,
480 },
481 #[tag(6)]
484 CalldataCopy {
485 #[tag(0)]
486 destination_address: MemoryAddress,
487 #[tag(1)]
488 size_address: MemoryAddress,
489 #[tag(2)]
490 offset_address: MemoryAddress,
491 },
492 #[tag(7)]
498 Call {
499 #[tag(0)]
500 location: Label,
501 },
502 #[tag(8)]
504 Const {
505 #[tag(0)]
506 destination: MemoryAddress,
507 #[tag(1)]
508 bit_size: BitSize,
509 #[tag(2)]
510 value: F,
511 },
512 #[tag(9)]
514 IndirectConst {
515 #[tag(0)]
516 destination_pointer: MemoryAddress,
517 #[tag(1)]
518 bit_size: BitSize,
519 #[tag(2)]
520 value: F,
521 },
522 #[tag(10)]
526 Return,
527 #[tag(11)]
532 ForeignCall {
533 #[tag(0)]
536 function: String,
537 #[tag(1)]
543 destinations: Vec<ValueOrArray>,
544 #[tag(2)]
546 destination_value_types: Vec<HeapValueType>,
547 #[tag(3)]
549 inputs: Vec<ValueOrArray>,
550 #[tag(4)]
553 input_value_types: Vec<HeapValueType>,
554 },
555 #[tag(12)]
557 Mov {
558 #[tag(0)]
559 destination: MemoryAddress,
560 #[tag(1)]
561 source: MemoryAddress,
562 },
563 #[tag(13)]
569 ConditionalMov {
570 #[tag(0)]
571 destination: MemoryAddress,
572 #[tag(1)]
573 source_a: MemoryAddress,
574 #[tag(2)]
575 source_b: MemoryAddress,
576 #[tag(3)]
577 condition: MemoryAddress,
578 },
579 #[tag(14)]
582 Load {
583 #[tag(0)]
584 destination: MemoryAddress,
585 #[tag(1)]
586 source_pointer: MemoryAddress,
587 },
588 #[tag(15)]
591 Store {
592 #[tag(0)]
593 destination_pointer: MemoryAddress,
594 #[tag(1)]
595 source: MemoryAddress,
596 },
597 #[tag(16)]
600 BlackBox(BlackBoxOp),
601 #[tag(17)]
603 Trap {
604 #[tag(0)]
605 revert_data: HeapVector,
606 },
607 #[tag(18)]
609 Stop {
610 #[tag(0)]
611 return_data: HeapVector,
612 },
613}
614
615impl<F: std::fmt::Display> std::fmt::Display for BrilligOpcode<F> {
616 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
617 match self {
618 BrilligOpcode::BinaryFieldOp { destination, op, lhs, rhs } => {
619 write!(f, "{destination} = field {op} {lhs}, {rhs}")
620 }
621 BrilligOpcode::BinaryIntOp { destination, op, bit_size, lhs, rhs } => {
622 write!(f, "{destination} = {bit_size} {op} {lhs}, {rhs}")
623 }
624 BrilligOpcode::Not { destination, source, bit_size } => {
625 write!(f, "{destination} = {bit_size} not {source}")
626 }
627 BrilligOpcode::Cast { destination, source, bit_size } => {
628 write!(f, "{destination} = cast {source} to {bit_size}")
629 }
630 BrilligOpcode::JumpIf { condition, location } => {
631 write!(f, "jump if {condition} to {location}")
632 }
633 BrilligOpcode::Jump { location } => {
634 write!(f, "jump to {location}")
635 }
636 BrilligOpcode::CalldataCopy { destination_address, size_address, offset_address } => {
637 write!(
638 f,
639 "{destination_address} = calldata copy [{offset_address}; {size_address}]"
640 )
641 }
642 BrilligOpcode::Call { location } => {
643 write!(f, "call {location}")
644 }
645 BrilligOpcode::Const { destination, bit_size, value } => {
646 write!(f, "{destination} = const {bit_size} {value}")
647 }
648 BrilligOpcode::IndirectConst { destination_pointer, bit_size, value } => {
649 write!(f, "{destination_pointer} = indirect const {bit_size} {value}")
650 }
651 BrilligOpcode::Return => {
652 write!(f, "return")
653 }
654 BrilligOpcode::ForeignCall {
655 function,
656 destinations,
657 destination_value_types,
658 inputs,
659 input_value_types,
660 } => {
661 if !destinations.is_empty() {
662 for (index, (destination, destination_value_type)) in
663 destinations.iter().zip_eq(destination_value_types).enumerate()
664 {
665 if index > 0 {
666 write!(f, ", ")?;
667 }
668 write!(f, "{destination}: {destination_value_type}")?;
669 }
670 write!(f, " = ")?;
671 }
672
673 write!(f, "foreign call {function}(")?;
674
675 for (index, (input, input_value_type)) in
676 inputs.iter().zip_eq(input_value_types).enumerate()
677 {
678 if index > 0 {
679 write!(f, ", ")?;
680 }
681 write!(f, "{input}: {input_value_type}")?;
682 }
683
684 write!(f, ")")?;
685 Ok(())
686 }
687 BrilligOpcode::Mov { destination, source } => {
688 write!(f, "{destination} = {source}")
689 }
690 BrilligOpcode::ConditionalMov { destination, source_a, source_b, condition } => {
691 write!(f, "{destination} = if {condition} then {source_a} else {source_b}")
692 }
693 BrilligOpcode::Load { destination, source_pointer } => {
694 write!(f, "{destination} = load {source_pointer}")
695 }
696 BrilligOpcode::Store { destination_pointer, source } => {
697 write!(f, "store {source} at {destination_pointer}")
698 }
699 BrilligOpcode::BlackBox(black_box_op) => {
700 write!(f, "{black_box_op}")
701 }
702 BrilligOpcode::Trap { revert_data } => {
703 write!(f, "trap {revert_data}")
704 }
705 BrilligOpcode::Stop { return_data } => {
706 write!(f, "stop {return_data}")
707 }
708 }
709 }
710}
711
712#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
718#[derive(Serialize, Deserialize, MsgpackTagged)]
719#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
720pub enum BinaryFieldOp {
721 #[tag(0)]
722 Add,
723 #[tag(1)]
724 Sub,
725 #[tag(2)]
726 Mul,
727 #[tag(3)]
729 Div,
730 #[tag(4)]
732 IntegerDiv,
733 #[tag(5)]
735 Equals,
736 #[tag(6)]
738 LessThan,
739 #[tag(7)]
741 LessThanEquals,
742}
743
744impl std::fmt::Display for BinaryFieldOp {
745 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
746 match self {
747 BinaryFieldOp::Add => write!(f, "add"),
748 BinaryFieldOp::Sub => write!(f, "sub"),
749 BinaryFieldOp::Mul => write!(f, "mul"),
750 BinaryFieldOp::Div => write!(f, "field_div"),
751 BinaryFieldOp::IntegerDiv => write!(f, "int_div"),
752 BinaryFieldOp::Equals => write!(f, "eq"),
753 BinaryFieldOp::LessThan => write!(f, "lt"),
754 BinaryFieldOp::LessThanEquals => write!(f, "lt_eq"),
755 }
756 }
757}
758
759#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
761#[derive(Serialize, Deserialize, MsgpackTagged)]
762#[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))]
763pub enum BinaryIntOp {
764 #[tag(0)]
765 Add,
766 #[tag(1)]
767 Sub,
768 #[tag(2)]
769 Mul,
770 #[tag(3)]
771 Div,
772 #[tag(4)]
774 Equals,
775 #[tag(5)]
777 LessThan,
778 #[tag(6)]
780 LessThanEquals,
781 #[tag(7)]
783 And,
784 #[tag(8)]
786 Or,
787 #[tag(9)]
789 Xor,
790 #[tag(10)]
792 Shl,
793 #[tag(11)]
795 Shr,
796}
797
798impl std::fmt::Display for BinaryIntOp {
799 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
800 match self {
801 BinaryIntOp::Add => write!(f, "add"),
802 BinaryIntOp::Sub => write!(f, "sub"),
803 BinaryIntOp::Mul => write!(f, "mul"),
804 BinaryIntOp::Div => write!(f, "div"),
805 BinaryIntOp::Equals => write!(f, "eq"),
806 BinaryIntOp::LessThan => write!(f, "lt"),
807 BinaryIntOp::LessThanEquals => write!(f, "lt_eq"),
808 BinaryIntOp::And => write!(f, "and"),
809 BinaryIntOp::Or => write!(f, "or"),
810 BinaryIntOp::Xor => write!(f, "xor"),
811 BinaryIntOp::Shl => write!(f, "shl"),
812 BinaryIntOp::Shr => write!(f, "shr"),
813 }
814 }
815}
816
817#[cfg(test)]
818mod tests {
819 use crate::MemoryAddress;
820
821 use super::{BitSize, IntegerBitSize};
822 use acir_field::FieldElement;
823
824 #[test]
826 fn test_integer_bitsize_roundtrip() {
827 let integer_sizes = [
828 IntegerBitSize::U1,
829 IntegerBitSize::U8,
830 IntegerBitSize::U16,
831 IntegerBitSize::U32,
832 IntegerBitSize::U64,
833 IntegerBitSize::U128,
834 ];
835
836 for int_size in integer_sizes {
837 let as_u32: u32 = int_size.into();
839 let roundtrip = IntegerBitSize::try_from(as_u32)
841 .expect("Should successfully convert back from u32");
842 assert_eq!(
843 int_size, roundtrip,
844 "IntegerBitSize::{int_size} should roundtrip through From<IntegerBitSize> for u32 and TryFrom<u32>"
845 );
846 }
847 }
848
849 #[test]
850 fn test_integer_bitsize_values() {
851 assert_eq!(u32::from(IntegerBitSize::U1), 1);
853 assert_eq!(u32::from(IntegerBitSize::U8), 8);
854 assert_eq!(u32::from(IntegerBitSize::U16), 16);
855 assert_eq!(u32::from(IntegerBitSize::U32), 32);
856 assert_eq!(u32::from(IntegerBitSize::U64), 64);
857 assert_eq!(u32::from(IntegerBitSize::U128), 128);
858 }
859
860 #[test]
861 fn test_integer_bitsize_try_from_invalid() {
862 assert!(IntegerBitSize::try_from(0).is_err());
864 assert!(IntegerBitSize::try_from(2).is_err());
865 assert!(IntegerBitSize::try_from(7).is_err());
866 assert!(IntegerBitSize::try_from(15).is_err());
867 assert!(IntegerBitSize::try_from(31).is_err());
868 assert!(IntegerBitSize::try_from(63).is_err());
869 assert!(IntegerBitSize::try_from(127).is_err());
870 assert!(IntegerBitSize::try_from(129).is_err());
871 assert!(IntegerBitSize::try_from(256).is_err());
872 }
873
874 #[test]
876 fn test_bitsize_roundtrip() {
877 let integer_sizes = [
879 IntegerBitSize::U1,
880 IntegerBitSize::U8,
881 IntegerBitSize::U16,
882 IntegerBitSize::U32,
883 IntegerBitSize::U64,
884 IntegerBitSize::U128,
885 ];
886
887 for int_size in integer_sizes {
888 let bit_size = BitSize::Integer(int_size);
889 let as_u32 = bit_size.to_u32::<FieldElement>();
890 let roundtrip = BitSize::try_from_u32::<FieldElement>(as_u32)
891 .expect("Should successfully convert back from u32");
892 assert_eq!(
893 bit_size, roundtrip,
894 "BitSize::Integer({int_size}) should roundtrip through to_u32/try_from_u32"
895 );
896 }
897
898 let field_bit_size = BitSize::Field;
900 let as_u32 = field_bit_size.to_u32::<FieldElement>();
901 let roundtrip = BitSize::try_from_u32::<FieldElement>(as_u32)
902 .expect("Should successfully convert Field back from u32");
903 assert_eq!(
904 field_bit_size, roundtrip,
905 "BitSize::Field should roundtrip through to_u32/try_from_u32"
906 );
907 }
908
909 #[test]
910 fn test_bitsize_to_u32_values_integers() {
911 assert_eq!(BitSize::Integer(IntegerBitSize::U1).to_u32::<FieldElement>(), 1);
913 assert_eq!(BitSize::Integer(IntegerBitSize::U8).to_u32::<FieldElement>(), 8);
914 assert_eq!(BitSize::Integer(IntegerBitSize::U16).to_u32::<FieldElement>(), 16);
915 assert_eq!(BitSize::Integer(IntegerBitSize::U32).to_u32::<FieldElement>(), 32);
916 assert_eq!(BitSize::Integer(IntegerBitSize::U64).to_u32::<FieldElement>(), 64);
917 assert_eq!(BitSize::Integer(IntegerBitSize::U128).to_u32::<FieldElement>(), 128);
918 }
919
920 #[test]
921 #[cfg(feature = "bn254")]
922 fn test_bitsize_to_u32_field_bn254() {
923 assert_eq!(BitSize::Field.to_u32::<FieldElement>(), 254);
925 }
926
927 #[test]
928 #[cfg(feature = "bls12_381")]
929 fn test_bitsize_to_u32_field_bls12_381() {
930 assert_eq!(BitSize::Field.to_u32::<FieldElement>(), 255);
932 }
933
934 #[test]
935 fn test_bitsize_try_from_u32_invalid() {
936 assert!(BitSize::try_from_u32::<FieldElement>(2).is_err());
938 assert!(BitSize::try_from_u32::<FieldElement>(7).is_err());
939 assert!(BitSize::try_from_u32::<FieldElement>(0).is_err());
940 assert!(BitSize::try_from_u32::<FieldElement>(256).is_err());
941 }
942
943 #[test]
944 #[should_panic = "memory offset overflow"]
945 fn memory_offset_overflow() {
946 let addr = MemoryAddress::direct(u32::MAX);
947 let _ = addr.offset(1);
948 }
949}
950
951#[cfg(feature = "arb")]
952mod prop_tests {
953 use proptest::arbitrary::Arbitrary;
954 use proptest::prelude::*;
955
956 use crate::lengths::SemanticLength;
957
958 use super::{BitSize, HeapValueType};
959
960 impl Arbitrary for HeapValueType {
962 type Parameters = ();
963 type Strategy = BoxedStrategy<Self>;
964
965 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
966 let leaf = any::<BitSize>().prop_map(HeapValueType::Simple);
967 leaf.prop_recursive(2, 3, 2, |inner| {
968 prop_oneof![
969 (prop::collection::vec(inner.clone(), 1..3), any::<u32>()).prop_map(
970 |(value_types, size)| {
971 HeapValueType::Array { value_types, size: SemanticLength(size) }
972 }
973 ),
974 (prop::collection::vec(inner, 1..3))
975 .prop_map(|value_types| { HeapValueType::Vector { value_types } }),
976 ]
977 })
978 .boxed()
979 }
980 }
981}