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 }