mod.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  mod bytes;
 20  mod parse;
 21  pub(crate) mod serialize;
 22  
 23  use crate::{LiteralType, PlaintextType, U32};
 24  use alphavm_console_network::prelude::*;
 25  
 26  use core::fmt::{Debug, Display};
 27  
 28  /// An `ArrayType` defines the type and size of an array.
 29  #[derive(Clone, PartialEq, Eq, Hash)]
 30  pub struct ArrayType<N: Network> {
 31      /// The element type.
 32      element_type: Box<PlaintextType<N>>,
 33      /// The length of the array.
 34      length: U32<N>,
 35  }
 36  
 37  impl<N: Network> ArrayType<N> {
 38      /// Returns `true` if the `ArrayType` is a bit array.
 39      pub const fn is_bit_array(&self) -> bool {
 40          matches!(self.next_element_type(), PlaintextType::Literal(LiteralType::Boolean))
 41      }
 42  
 43      /// Returns `true` if the `ArrayType` contains a string type.
 44      pub fn contains_string_type(&self) -> bool {
 45          // Initialize depth counter and current array type.
 46          let mut array_type = self;
 47  
 48          // Check nested array types up to the maximum data depth.
 49          for _ in 0..=N::MAX_DATA_DEPTH {
 50              // Check if the current element type is a string type.
 51              if array_type.next_element_type().contains_string_type() {
 52                  return true;
 53              }
 54              // If the next element is an array, continue to the next depth. Otherwise, we can stop checking.
 55              if let PlaintextType::Array(next) = array_type.next_element_type() {
 56                  array_type = next;
 57              } else {
 58                  return false;
 59              }
 60          }
 61          // If we reach here, it means we've exceeded the maximum depth without finding a non-array type.
 62          true
 63      }
 64  
 65      /// Returns `true` if the `ArrayType` contains an array type with a size that exceeds the given maximum.
 66      pub fn exceeds_max_array_size(&self, max_array_size: u32) -> bool {
 67          // Initialize depth counter and current array type.
 68          let mut array_type = self;
 69  
 70          // Check nested array types up to the maximum data depth.
 71          for _ in 0..=N::MAX_DATA_DEPTH {
 72              // Check if the current array's length exceeds the maximum allowed size.
 73              if **array_type.length() > max_array_size {
 74                  return true;
 75              }
 76              // If the next element is an array, continue to the next depth. Otherwise, we can stop checking.
 77              if let PlaintextType::Array(next) = array_type.next_element_type() {
 78                  array_type = next;
 79              } else {
 80                  return false;
 81              }
 82          }
 83          // If we reach here, it means we've exceeded the maximum depth without finding a non-array type.
 84          true
 85      }
 86  }
 87  
 88  impl<N: Network> ArrayType<N> {
 89      /// Initializes a new multi-dimensional array type.
 90      /// Note that the dimensions must be specified from the outermost to the innermost.
 91      pub fn new(plaintext_type: PlaintextType<N>, mut dimensions: Vec<U32<N>>) -> Result<Self> {
 92          // Check that the number of dimensions are valid.
 93          ensure!(!dimensions.is_empty(), "An array must have at least one dimension");
 94          ensure!(dimensions.len() <= N::MAX_DATA_DEPTH, "An array can have at most {} dimensions", N::MAX_DATA_DEPTH);
 95          // Check that each dimension is valid.
 96          for length in &dimensions {
 97              ensure!(**length as usize >= N::MIN_ARRAY_ELEMENTS, "An array must have {} element", N::MIN_ARRAY_ELEMENTS);
 98              ensure!(
 99                  **length as usize <= N::MAX_ARRAY_ELEMENTS,
100                  "An array can contain {} elements",
101                  N::MAX_ARRAY_ELEMENTS
102              );
103          }
104          // Construct the array type.
105          // Note that this `unwrap` is safe because we have already checked that the number of dimensions is greater than zero.
106          let array_type = Self { element_type: Box::new(plaintext_type), length: dimensions.pop().unwrap() };
107          Ok(dimensions.into_iter().rev().fold(array_type, |array_type, dimension| Self {
108              element_type: Box::new(PlaintextType::Array(array_type)),
109              length: dimension,
110          }))
111      }
112  }
113  
114  impl<N: Network> ArrayType<N> {
115      /// Returns the next element type.
116      /// In the case of a one-dimensional array, this will return the element type of the array.
117      /// In the case of a multi-dimensional array, this will return the element type of the **outermost** array.
118      pub const fn next_element_type(&self) -> &PlaintextType<N> {
119          &self.element_type
120      }
121  
122      /// Returns the base element type.
123      /// In the case of a one-dimensional array, this will return the element type of the array.
124      /// In the case of a multi-dimensional array, this will return the element type of the **innermost** array.
125      pub fn base_element_type(&self) -> &PlaintextType<N> {
126          let mut element_type = self.next_element_type();
127          // Note that this `while` loop must terminate because the number of dimensions of `ArrayType` is checked to be less then N::MAX_DATA_DEPTH.
128          while let PlaintextType::Array(array_type) = element_type {
129              element_type = array_type.next_element_type();
130          }
131          element_type
132      }
133  
134      /// Returns `true` if the array is empty.
135      pub fn is_empty(&self) -> bool {
136          self.length.is_zero()
137      }
138  
139      /// Returns the length of the array.
140      pub const fn length(&self) -> &U32<N> {
141          &self.length
142      }
143  }
144  
145  #[cfg(test)]
146  mod tests {
147      use super::*;
148      use crate::{Identifier, LiteralType};
149      use alphavm_console_network::MainnetV0;
150  
151      use core::str::FromStr;
152  
153      type CurrentNetwork = MainnetV0;
154  
155      #[test]
156      fn test_array_type() -> Result<()> {
157          // Test literal array types.
158          let array = ArrayType::<CurrentNetwork>::from_str("[field; 4u32]")?;
159          assert_eq!(array, ArrayType::<CurrentNetwork>::new(PlaintextType::from_str("field")?, vec![U32::new(4)])?);
160          assert_eq!(
161              array.to_bytes_le()?,
162              ArrayType::<CurrentNetwork>::from_bytes_le(&array.to_bytes_le()?)?.to_bytes_le()?
163          );
164          assert_eq!(array.next_element_type(), &PlaintextType::Literal(LiteralType::Field));
165          assert_eq!(array.length(), &U32::new(4));
166          assert!(!array.is_empty());
167  
168          // Test struct array types.
169          let array = ArrayType::<CurrentNetwork>::from_str("[foo; 1u32]")?;
170          assert_eq!(array, ArrayType::<CurrentNetwork>::new(PlaintextType::from_str("foo")?, vec![U32::new(1)])?);
171          assert_eq!(
172              array.to_bytes_le()?,
173              ArrayType::<CurrentNetwork>::from_bytes_le(&array.to_bytes_le()?)?.to_bytes_le()?
174          );
175          assert_eq!(array.next_element_type(), &PlaintextType::Struct(Identifier::from_str("foo")?));
176          assert_eq!(array.length(), &U32::new(1));
177          assert!(!array.is_empty());
178  
179          // Test array type with maximum length.
180          let array = ArrayType::<CurrentNetwork>::from_str("[scalar; 32u32]")?;
181          assert_eq!(array, ArrayType::<CurrentNetwork>::new(PlaintextType::from_str("scalar")?, vec![U32::new(32)])?);
182          assert_eq!(
183              array.to_bytes_le()?,
184              ArrayType::<CurrentNetwork>::from_bytes_le(&array.to_bytes_le()?)?.to_bytes_le()?
185          );
186          assert_eq!(array.next_element_type(), &PlaintextType::Literal(LiteralType::Scalar));
187          assert_eq!(array.length(), &U32::new(32));
188          assert!(!array.is_empty());
189  
190          // Test multi-dimensional array types.
191          let array = ArrayType::<CurrentNetwork>::from_str("[[field; 2u32]; 3u32]")?;
192          assert_eq!(
193              array,
194              ArrayType::<CurrentNetwork>::new(
195                  PlaintextType::Array(ArrayType::<CurrentNetwork>::new(PlaintextType::from_str("field")?, vec![
196                      U32::new(2)
197                  ])?),
198                  vec![U32::new(3)]
199              )?
200          );
201          assert_eq!(
202              array.to_bytes_le()?,
203              ArrayType::<CurrentNetwork>::from_bytes_le(&array.to_bytes_le()?)?.to_bytes_le()?
204          );
205          assert_eq!(array.to_string(), "[[field; 2u32]; 3u32]");
206          assert_eq!(
207              array.next_element_type(),
208              &PlaintextType::Array(ArrayType::<CurrentNetwork>::new(PlaintextType::Literal(LiteralType::Field), vec![
209                  U32::new(2)
210              ])?)
211          );
212          assert_eq!(array.length(), &U32::new(3));
213          assert!(!array.is_empty());
214  
215          Ok(())
216      }
217  
218      #[test]
219      fn test_array_type_fails() {
220          let type_ = ArrayType::<CurrentNetwork>::from_str("[field; 0u32]");
221          assert!(type_.is_err());
222  
223          let type_ = ArrayType::<CurrentNetwork>::from_str("[field; 4294967296u32]");
224          assert!(type_.is_err());
225  
226          let type_ = ArrayType::<CurrentNetwork>::from_str("[foo; -1i32]");
227          assert!(type_.is_err());
228  
229          let type_ = ArrayType::<CurrentNetwork>::from_str("[foo; 1u8]");
230          assert!(type_.is_err());
231      }
232  }