/ console / program / src / data / identifier / mod.rs
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 equal;
 21  mod from_bits;
 22  mod from_field;
 23  mod parse;
 24  mod serialize;
 25  mod size_in_bits;
 26  mod to_bits;
 27  mod to_field;
 28  
 29  use alphavm_console_network::Network;
 30  use alphavm_console_types::{prelude::*, Field};
 31  
 32  /// An identifier is an **immutable** UTF-8 string,
 33  /// represented as a **constant** field element in the CurrentNetwork.
 34  ///
 35  /// # Requirements
 36  /// The identifier must not be an empty string.
 37  /// The identifier must not start with a number.
 38  /// The identifier must be alphanumeric, and may include underscores.
 39  /// The identifier must not consist solely of underscores.
 40  /// The identifier must fit within the data capacity of a base field element.
 41  #[derive(Copy, Clone)]
 42  pub struct Identifier<N: Network>(Field<N>, u8); // Number of bytes in the identifier.
 43  
 44  impl<N: Network> From<&Identifier<N>> for Identifier<N> {
 45      /// Returns a copy of the identifier.
 46      fn from(identifier: &Identifier<N>) -> Self {
 47          *identifier
 48      }
 49  }
 50  
 51  impl<N: Network> TryFrom<String> for Identifier<N> {
 52      type Error = Error;
 53  
 54      /// Initializes an identifier from a string.
 55      fn try_from(identifier: String) -> Result<Self> {
 56          Self::from_str(&identifier)
 57      }
 58  }
 59  
 60  impl<N: Network> TryFrom<&String> for Identifier<N> {
 61      type Error = Error;
 62  
 63      /// Initializes an identifier from a string.
 64      fn try_from(identifier: &String) -> Result<Self> {
 65          Self::from_str(identifier)
 66      }
 67  }
 68  
 69  impl<N: Network> TryFrom<&str> for Identifier<N> {
 70      type Error = Error;
 71  
 72      /// Initializes an identifier from a string.
 73      fn try_from(identifier: &str) -> Result<Self> {
 74          Self::from_str(identifier)
 75      }
 76  }
 77  
 78  #[cfg(test)]
 79  pub(crate) mod tests {
 80      use super::*;
 81      use alphavm_console_network::MainnetV0;
 82  
 83      type CurrentNetwork = MainnetV0;
 84  
 85      const ITERATIONS: usize = 100;
 86  
 87      /// Samples a random identifier.
 88      pub(crate) fn sample_identifier<N: Network>(rng: &mut TestRng) -> Result<Identifier<N>> {
 89          // Sample a random fixed-length alphanumeric string, that always starts with an alphabetic character.
 90          let string = sample_identifier_as_string::<N>(rng)?;
 91          // Recover the field element from the bits.
 92          let field = Field::<N>::from_bits_le(&string.as_bytes().to_bits_le())?;
 93          // Return the identifier.
 94          Ok(Identifier(field, u8::try_from(string.len()).or_halt_with::<CurrentNetwork>("Invalid identifier length")))
 95      }
 96  
 97      /// Samples a random identifier as a string.
 98      pub(crate) fn sample_identifier_as_string<N: Network>(rng: &mut TestRng) -> Result<String> {
 99          // Sample a random fixed-length alphanumeric string, that always starts with an alphabetic character.
100          let string = "a".to_string()
101              + &rng
102                  .sample_iter(&Alphanumeric)
103                  .take(Field::<N>::size_in_data_bits() / (8 * 2))
104                  .map(char::from)
105                  .collect::<String>();
106          // Ensure identifier fits within the data capacity of the base field.
107          let max_bytes = Field::<N>::size_in_data_bits() / 8; // Note: This intentionally rounds down.
108          match string.len() <= max_bytes {
109              // Return the identifier.
110              true => Ok(string),
111              false => bail!("Identifier exceeds the maximum capacity allowed"),
112          }
113      }
114  
115      /// Samples a random lowercase identifier as a string.
116      pub(crate) fn sample_lowercase_identifier_as_string<N: Network>(rng: &mut TestRng) -> Result<String> {
117          // Sample a random identifier.
118          let string = sample_identifier_as_string::<N>(rng)?;
119          // Return the identifier as lowercase.
120          Ok(string.to_lowercase())
121      }
122  
123      #[test]
124      fn test_try_from() -> Result<()> {
125          let mut rng = TestRng::default();
126  
127          for _ in 0..ITERATIONS {
128              // Sample a random fixed-length alphanumeric string, that always starts with an alphabetic character.
129              let expected_string = sample_identifier_as_string::<CurrentNetwork>(&mut rng)?;
130              // Recover the field element from the bits.
131              let expected_field = Field::<CurrentNetwork>::from_bits_le(&expected_string.as_bytes().to_bits_le())?;
132  
133              // Try to initialize an identifier from the string.
134              let candidate = Identifier::<CurrentNetwork>::try_from(expected_string.as_str())?;
135              assert_eq!(expected_field, candidate.0);
136              assert_eq!(expected_string.len(), candidate.1 as usize);
137          }
138          Ok(())
139      }
140  
141      #[test]
142      fn test_identifier_try_from_illegal() {
143          assert!(Identifier::<CurrentNetwork>::try_from("123").is_err());
144          assert!(Identifier::<CurrentNetwork>::try_from("abc\x08def").is_err());
145          assert!(Identifier::<CurrentNetwork>::try_from("abc\u{202a}def").is_err());
146      }
147  }