/ console / program / src / data / plaintext / from_bits.rs
from_bits.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use super::*;
 17  
 18  impl<N: Network> FromBits for Plaintext<N> {
 19      /// Initializes a new plaintext from a list of little-endian bits *without* trailing zeros.
 20      fn from_bits_le(bits_le: &[bool]) -> Result<Self> {
 21          Self::from_bits_le_internal(bits_le, 0)
 22      }
 23  
 24      /// Initializes a new plaintext from a list of big-endian bits *without* trailing zeros.
 25      fn from_bits_be(bits_be: &[bool]) -> Result<Self> {
 26          Self::from_bits_be_internal(bits_be, 0)
 27      }
 28  }
 29  
 30  impl<N: Network> Plaintext<N> {
 31      /// Initializes a new plaintext from a list of little-endian bits *without* trailing zeros, while the depth of the data.
 32      fn from_bits_le_internal(bits_le: &[bool], depth: usize) -> Result<Self> {
 33          // Ensure that the depth is within the maximum limit.
 34          if depth > N::MAX_DATA_DEPTH {
 35              bail!("Plaintext depth exceeds maximum limit: {}", N::MAX_DATA_DEPTH)
 36          }
 37  
 38          let bits = bits_le;
 39  
 40          // The starting index used to create subsequent subslices of the `bits` slice.
 41          let mut index = 0;
 42  
 43          // Helper function to get the next n bits as a slice.
 44          let mut next_bits = |n: usize| -> Result<&[bool]> {
 45              // Safely procure a subslice with the length `n` starting at `index`.
 46              let subslice = bits.get(index..index + n);
 47              // Check if the range is within bounds.
 48              if let Some(next_bits) = subslice {
 49                  // Move the starting index.
 50                  index += n;
 51                  // Return the subslice.
 52                  Ok(next_bits)
 53              } else {
 54                  bail!("Insufficient bits");
 55              }
 56          };
 57  
 58          let variant = next_bits(2)?;
 59          let variant = [variant[0], variant[1]];
 60  
 61          // Literal
 62          if variant == PlaintextType::<N>::LITERAL_PREFIX_BITS {
 63              let literal_variant = u8::from_bits_le(next_bits(8)?)?;
 64              let literal_size = u16::from_bits_le(next_bits(16)?)?;
 65              let literal = Literal::from_bits_le(literal_variant, next_bits(literal_size as usize)?)?;
 66  
 67              // Cache the plaintext bits, and return the literal.
 68              Ok(Self::Literal(literal, bits_le.to_vec().into()))
 69          }
 70          // Struct
 71          else if variant == PlaintextType::<N>::STRUCT_PREFIX_BITS {
 72              let num_members = u8::from_bits_le(next_bits(8)?)?;
 73              if num_members as usize > N::MAX_STRUCT_ENTRIES {
 74                  bail!("Struct exceeds maximum of entries.");
 75              }
 76  
 77              let mut members = IndexMap::with_capacity(num_members as usize);
 78              for _ in 0..num_members {
 79                  let identifier_size = u8::from_bits_le(next_bits(8)?)?;
 80                  let identifier = Identifier::from_bits_le(next_bits(identifier_size as usize)?)?;
 81  
 82                  let member_size = u16::from_bits_le(next_bits(16)?)?;
 83                  let value = Plaintext::from_bits_le_internal(next_bits(member_size as usize)?, depth + 1)?;
 84  
 85                  if members.insert(identifier, value).is_some() {
 86                      bail!("Duplicate identifier in struct.");
 87                  }
 88              }
 89  
 90              // Cache the plaintext bits, and return the struct.
 91              Ok(Self::Struct(members, bits_le.to_vec().into()))
 92          }
 93          // Array
 94          else if variant == PlaintextType::<N>::ARRAY_PREFIX_BITS {
 95              let num_elements = u32::from_bits_le(next_bits(32)?)?;
 96              if num_elements as usize > N::MAX_ARRAY_ELEMENTS {
 97                  bail!("Array exceeds maximum of elements.");
 98              }
 99  
100              let mut elements = Vec::with_capacity(num_elements as usize);
101              for _ in 0..num_elements {
102                  let element_size = u16::from_bits_le(next_bits(16)?)?;
103                  let element = Plaintext::from_bits_le_internal(next_bits(element_size as usize)?, depth + 1)?;
104  
105                  elements.push(element);
106              }
107  
108              // Cache the plaintext bits, and return the array.
109              Ok(Self::Array(elements, bits_le.to_vec().into()))
110          }
111          // Unknown variant.
112          else {
113              bail!("Unknown plaintext variant - {variant:?}");
114          }
115      }
116  
117      /// Initializes a new plaintext from a list of big-endian bits *without* trailing zeros, while tracking the depth of the data.
118      fn from_bits_be_internal(bits_be: &[bool], depth: usize) -> Result<Self> {
119          // Ensure that the depth is within the maximum limit.
120          if depth > N::MAX_DATA_DEPTH {
121              bail!("Plaintext depth exceeds maximum limit: {}", N::MAX_DATA_DEPTH)
122          }
123  
124          let bits = bits_be;
125  
126          // The starting index used to create subsequent subslices of the `bits` slice.
127          let mut index = 0;
128  
129          // Helper function to get the next n bits as a slice.
130          let mut next_bits = |n: usize| -> Result<&[bool]> {
131              // Safely procure a subslice with the length `n` starting at `index`.
132              let subslice = bits.get(index..index + n);
133              // Check if the range is within bounds.
134              if let Some(next_bits) = subslice {
135                  // Move the starting index.
136                  index += n;
137                  // Return the subslice.
138                  Ok(next_bits)
139              } else {
140                  bail!("Insufficient bits");
141              }
142          };
143  
144          let variant = next_bits(2)?;
145          let variant = [variant[0], variant[1]];
146  
147          // Literal
148          if variant == PlaintextType::<N>::LITERAL_PREFIX_BITS {
149              let literal_variant = u8::from_bits_be(next_bits(8)?)?;
150              let literal_size = u16::from_bits_be(next_bits(16)?)?;
151              let literal = Literal::from_bits_be(literal_variant, next_bits(literal_size as usize)?)?;
152  
153              // Cache the plaintext bits, and return the literal.
154              Ok(Self::Literal(literal, bits_be.to_vec().into()))
155          }
156          // Struct
157          else if variant == PlaintextType::<N>::STRUCT_PREFIX_BITS {
158              let num_members = u8::from_bits_be(next_bits(8)?)?;
159              if num_members as usize > N::MAX_STRUCT_ENTRIES {
160                  bail!("Struct exceeds maximum of entries.");
161              }
162              let mut members = IndexMap::with_capacity(num_members as usize);
163              for _ in 0..num_members {
164                  let identifier_size = u8::from_bits_be(next_bits(8)?)?;
165                  let identifier = Identifier::from_bits_be(next_bits(identifier_size as usize)?)?;
166                  let member_size = u16::from_bits_be(next_bits(16)?)?;
167                  let value = Plaintext::from_bits_be_internal(next_bits(member_size as usize)?, depth + 1)?;
168                  if members.insert(identifier, value).is_some() {
169                      bail!("Duplicate identifier in struct.");
170                  }
171              }
172  
173              // Cache the plaintext bits, and return the struct.
174              Ok(Self::Struct(members, bits_be.to_vec().into()))
175          }
176          // Array
177          else if variant == PlaintextType::<N>::ARRAY_PREFIX_BITS {
178              let num_elements = u32::from_bits_be(next_bits(32)?)?;
179              if num_elements as usize > N::MAX_ARRAY_ELEMENTS {
180                  bail!("Array exceeds maximum of elements.");
181              }
182  
183              let mut elements = Vec::with_capacity(num_elements as usize);
184              for _ in 0..num_elements {
185                  let element_size = u16::from_bits_be(next_bits(16)?)?;
186                  let element = Plaintext::from_bits_be_internal(next_bits(element_size as usize)?, depth + 1)?;
187  
188                  elements.push(element);
189              }
190  
191              // Cache the plaintext bits, and return the array.
192              Ok(Self::Array(elements, bits_be.to_vec().into()))
193          }
194          // Unknown variant.
195          else {
196              bail!("Unknown plaintext variant - {variant:?}");
197          }
198      }
199  }
200  
201  #[cfg(test)]
202  mod tests {
203      use super::*;
204      use alphavm_console_network::MainnetV0;
205  
206      type CurrentNetwork = MainnetV0;
207  
208      // A helper function to get the depth of the plaintext.
209      fn get_depth(plaintext: &Plaintext<CurrentNetwork>) -> usize {
210          match plaintext {
211              Plaintext::Literal(_, _) => 0,
212              Plaintext::Struct(members, _) => members.values().map(get_depth).max().unwrap_or(0) + 1,
213              Plaintext::Array(elements, _) => elements.iter().map(get_depth).max().unwrap_or(0) + 1,
214          }
215      }
216  
217      #[test]
218      fn test_deeply_nested_plaintext_bits_le() {
219          // Creates a nested array-like `Plaintext` structure by wrapping a root value `depth` times.
220          fn create_nested_array(depth: usize, root: impl Display) -> Vec<bool> {
221              // Start from the innermost value.
222              let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bits_le();
223              // Reverse the bytes.
224              result.reverse();
225              // Build up the structure in reverse.
226              for _ in 0..depth {
227                  // Write the size of the object in bits in reverse.
228                  let mut length = (u16::try_from(result.len()).unwrap()).to_bits_le();
229                  length.reverse();
230                  result.extend(length);
231                  // Write the number of elements in the array in reverse.
232                  let mut num_elements = 1u32.to_bits_le();
233                  num_elements.reverse();
234                  result.extend(num_elements);
235                  // Write the plaintext variant in reverse.
236                  result.extend([false, true]);
237              }
238              // Reverse the result to get the correct order.
239              result.reverse();
240              result
241          }
242  
243          // Creates a nested struct-like `Plaintext` structure by wrapping a root value `depth` times.
244          fn create_nested_struct(depth: usize, root: impl Display) -> Vec<bool> {
245              // Start from the innermost value.
246              let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bits_le();
247              // Reverse the bytes.
248              result.reverse();
249              // Build up the structure in reverse.
250              for _ in 0..depth {
251                  // Write the size of the object in bits in reverse.
252                  let mut length = (u16::try_from(result.len()).unwrap()).to_bits_le();
253                  length.reverse();
254                  result.extend(length);
255                  // Write the member name in reverse.
256                  let mut member_name = Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bits_le();
257                  let mut member_name_length = u8::try_from(member_name.len()).unwrap().to_bits_le();
258                  member_name.reverse();
259                  result.extend(member_name);
260                  // Write the length of the member name in reverse.
261                  member_name_length.reverse();
262                  result.extend(member_name_length);
263                  // Write the number of members in the struct in reverse.
264                  let mut num_members = 1u8.to_bits_le();
265                  num_members.reverse();
266                  result.extend(num_members);
267                  // Write the plaintext variant in reverse.
268                  result.extend([true, false]);
269              }
270              // Reverse the result to get the correct order.
271              result.reverse();
272              result
273          }
274  
275          // Creates a nested `Plaintext` structure with alternating array and struct wrappers.
276          fn create_alternated_nested(depth: usize, root: impl Display) -> Vec<bool> {
277              // Start from the innermost value.
278              let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bits_le();
279              // Reverse the bytes.
280              result.reverse();
281              // Build up the structure in reverse.
282              for i in 0..depth {
283                  // Write the size of the object in bits in reverse.
284                  let mut length = (u16::try_from(result.len()).unwrap()).to_bits_le();
285                  length.reverse();
286                  result.extend(length);
287                  // Determine the type of the wrapper (array or struct) and handle accordingly.
288                  if i % 2 == 0 {
289                      // Write the number of elements in the array in reverse.
290                      let mut num_elements = 1u32.to_bits_le();
291                      num_elements.reverse();
292                      result.extend(num_elements);
293                      // Write the plaintext variant for array in reverse.
294                      result.extend([false, true]);
295                  } else {
296                      // Write the member name in reverse.
297                      let mut member_name = Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bits_le();
298                      let mut member_name_length = u8::try_from(member_name.len()).unwrap().to_bits_le();
299                      member_name.reverse();
300                      result.extend(member_name);
301                      // Write the member name length in reverse.
302                      member_name_length.reverse();
303                      result.extend(member_name_length);
304                      // Write the number of members in the struct in reverse.
305                      let mut num_members = 1u8.to_bits_le();
306                      num_members.reverse();
307                      result.extend(num_members);
308                      // Write the plaintext variant for struct in reverse.
309                      result.extend([true, false]);
310                  }
311              }
312              // Reverse the result to get the correct order.
313              result.reverse();
314              result
315          }
316  
317          // A helper function to run the test.
318          fn run_test(expected_depth: usize, input: Vec<bool>, expected_error: bool) {
319              // Parse the input string.
320              let result = Plaintext::<CurrentNetwork>::from_bits_le(&input);
321              // Check if the result is an error.
322              match expected_error {
323                  true => {
324                      assert!(result.is_err());
325                      return;
326                  }
327                  false => assert!(result.is_ok()),
328              };
329              // Unwrap the result.
330              let candidate = result.unwrap();
331              // Check if the candidate is equal to the input.
332              assert_eq!(input, candidate.to_bits_le());
333              // Check if the depth of the candidate is equal to the expected depth.
334              assert_eq!(get_depth(&candidate), expected_depth);
335          }
336  
337          // Initialize a sequence of depths to check.
338          // Note that 890 is approximate maximum depth that can be constructed in this test.
339          let mut depths = (0usize..100).collect_vec();
340          depths.extend((100..890).step_by(10));
341  
342          // Test deeply nested arrays with different literal types.
343          for i in depths.iter().copied() {
344              run_test(i, create_nested_array(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
345              run_test(i, create_nested_array(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
346              run_test(i, create_nested_array(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
347              run_test(i, create_nested_array(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
348          }
349  
350          // Test deeply nested structs with different literal types.
351          for i in depths.iter().copied() {
352              run_test(i, create_nested_struct(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
353              run_test(i, create_nested_struct(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
354              run_test(i, create_nested_struct(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
355              run_test(i, create_nested_struct(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
356          }
357  
358          // Test alternating nested arrays and structs.
359          for i in depths.iter().copied() {
360              run_test(i, create_alternated_nested(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
361              run_test(i, create_alternated_nested(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
362              run_test(i, create_alternated_nested(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
363              run_test(i, create_alternated_nested(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
364          }
365      }
366  
367      #[test]
368      fn test_deeply_nested_plaintext_bits_be() {
369          // Creates a nested array-like `Plaintext` structure by wrapping a root value `depth` times.
370          fn create_nested_array(depth: usize, root: impl Display) -> Vec<bool> {
371              // Start from the innermost value.
372              let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bits_be();
373              // Reverse the bits.
374              result.reverse();
375              // Build up the structure in reverse.
376              for _ in 0..depth {
377                  // Write the size of the object in bits in reverse.
378                  let mut length = (u16::try_from(result.len()).unwrap()).to_bits_be();
379                  length.reverse();
380                  result.extend(length);
381                  // Write the number of elements in the array in reverse.
382                  let mut num_elements = 1u32.to_bits_be();
383                  num_elements.reverse();
384                  result.extend(num_elements);
385                  // Write the plaintext variant in reverse.
386                  result.extend([false, true]);
387              }
388              // Reverse the result to get the correct order.
389              result.reverse();
390              result
391          }
392  
393          // Creates a nested struct-like `Plaintext` structure by wrapping a root value `depth` times.
394          fn create_nested_struct(depth: usize, root: impl Display) -> Vec<bool> {
395              // Start from the innermost value.
396              let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bits_be();
397              // Reverse the bytes.
398              result.reverse();
399              // Build up the structure in reverse.
400              for _ in 0..depth {
401                  // Write the size of the object in bits in reverse.
402                  let mut length = (u16::try_from(result.len()).unwrap()).to_bits_be();
403                  length.reverse();
404                  result.extend(length);
405                  // Write the member name in reverse.
406                  let mut member_name = Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bits_be();
407                  let mut member_name_length = u8::try_from(member_name.len()).unwrap().to_bits_be();
408                  member_name.reverse();
409                  result.extend(member_name);
410                  // Write the length of the member name in reverse.
411                  member_name_length.reverse();
412                  result.extend(member_name_length);
413                  // Write the number of members in the struct in reverse.
414                  let mut num_members = 1u8.to_bits_be();
415                  num_members.reverse();
416                  result.extend(num_members);
417                  // Write the plaintext variant in reverse.
418                  result.extend([true, false]);
419              }
420              // Reverse the result to get the correct order.
421              result.reverse();
422              result
423          }
424  
425          // Creates a nested `Plaintext` structure with alternating array and struct wrappers.
426          fn create_alternated_nested(depth: usize, root: impl Display) -> Vec<bool> {
427              // Start from the innermost value.
428              let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bits_be();
429              // Reverse the bytes.
430              result.reverse();
431              // Build up the structure in reverse.
432              for i in 0..depth {
433                  // Write the size of the object in bits in reverse.
434                  let mut length = (u16::try_from(result.len()).unwrap()).to_bits_be();
435                  length.reverse();
436                  result.extend(length);
437                  // Determine the type of the wrapper (array or struct) and handle accordingly.
438                  if i % 2 == 0 {
439                      // Write the number of elements in the array in reverse.
440                      let mut num_elements = 1u32.to_bits_be();
441                      num_elements.reverse();
442                      result.extend(num_elements);
443                      // Write the plaintext variant for array in reverse.
444                      result.extend([false, true]);
445                  } else {
446                      // Write the member name in reverse.
447                      let mut member_name = Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bits_be();
448                      let mut member_name_length = u8::try_from(member_name.len()).unwrap().to_bits_be();
449                      member_name.reverse();
450                      result.extend(member_name);
451                      // Write the member name length in reverse.
452                      member_name_length.reverse();
453                      result.extend(member_name_length);
454                      // Write the number of members in the struct in reverse.
455                      let mut num_members = 1u8.to_bits_be();
456                      num_members.reverse();
457                      result.extend(num_members);
458                      // Write the plaintext variant for struct in reverse.
459                      result.extend([true, false]);
460                  }
461              }
462              // Reverse the result to get the correct order.
463              result.reverse();
464              result
465          }
466  
467          // A helper function to run the test.
468          fn run_test(expected_depth: usize, input: Vec<bool>, expected_error: bool) {
469              // Parse the input string.
470              let result = Plaintext::<CurrentNetwork>::from_bits_be(&input);
471              // Check if the result is an error.
472              match expected_error {
473                  true => {
474                      assert!(result.is_err());
475                      return;
476                  }
477                  false => assert!(result.is_ok()),
478              };
479              // Unwrap the result.
480              let candidate = result.unwrap();
481              // Check if the candidate is equal to the input.
482              assert_eq!(input, candidate.to_bits_be());
483              // Check if the depth of the candidate is equal to the expected depth.
484              assert_eq!(get_depth(&candidate), expected_depth);
485          }
486  
487          // Initialize a sequence of depths to check.
488          // Note that 890 is approximate maximum depth that can be constructed in this test.
489          let mut depths = (0usize..100).collect_vec();
490          depths.extend((100..890).step_by(10));
491  
492          // Test deeply nested arrays with different literal types.
493          for i in depths.iter().copied() {
494              run_test(i, create_nested_array(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
495              run_test(i, create_nested_array(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
496              run_test(i, create_nested_array(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
497              run_test(i, create_nested_array(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
498          }
499  
500          // Test deeply nested structs with different literal types.
501          for i in depths.iter().copied() {
502              run_test(i, create_nested_struct(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
503              run_test(i, create_nested_struct(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
504              run_test(i, create_nested_struct(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
505              run_test(i, create_nested_struct(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
506          }
507  
508          // Test alternating nested arrays and structs.
509          for i in depths.iter().copied() {
510              run_test(i, create_alternated_nested(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
511              run_test(i, create_alternated_nested(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
512              run_test(i, create_alternated_nested(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
513              run_test(i, create_alternated_nested(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
514          }
515      }
516  }