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 }