mod.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm 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 #[cfg(test)] 17 use deltavm_circuit_types::environment::assert_scope; 18 19 mod equal; 20 mod from_bits; 21 mod from_field; 22 mod size_in_bits; 23 mod to_bits; 24 mod to_field; 25 26 use deltavm_circuit_network::Alpha; 27 use deltavm_circuit_types::{Boolean, Field, U8, environment::prelude::*}; 28 use deltavm_utilities::ToBits as TB; 29 30 /// An identifier is an **immutable** UTF-8 string, 31 /// represented as a **constant** field element in the circuit. 32 /// 33 /// # Requirements 34 /// The identifier must not be an empty string. 35 /// The identifier must not start with a number. 36 /// The identifier must be alphanumeric, and may include underscores. 37 /// The identifier must not consist solely of underscores. 38 /// The identifier must fit within the data capacity of a base field element. 39 #[derive(Clone)] 40 pub struct Identifier<A: Alpha>(Field<A>, u8); // Number of bytes in the identifier. 41 42 impl<A: Alpha> Inject for Identifier<A> { 43 type Primitive = console::Identifier<A::Network>; 44 45 /// Initializes a new identifier from a string. 46 /// Note: Identifiers are always `Mode::Constant`. 47 fn new(_: Mode, identifier: Self::Primitive) -> Self { 48 // Convert the identifier to a string to check its validity. 49 let identifier = identifier.to_string(); 50 51 // Note: The string bytes themselves are **not** little-endian. Rather, they are order-preserving 52 // for reconstructing the string when recovering the field element back into bytes. 53 let field = Field::from_bits_le(&Vec::<Boolean<_>>::constant(identifier.to_bits_le())); 54 55 // Return the identifier. 56 Self(field, identifier.len() as u8) 57 } 58 } 59 60 impl<A: Alpha> Eject for Identifier<A> { 61 type Primitive = console::Identifier<A::Network>; 62 63 /// Ejects the mode of the identifier. 64 fn eject_mode(&self) -> Mode { 65 debug_assert!(self.0.eject_mode() == Mode::Constant, "Identifier::eject_mode - Mode must be 'Constant'"); 66 Mode::Constant 67 } 68 69 /// Ejects the identifier as a string. 70 fn eject_value(&self) -> Self::Primitive { 71 match console::FromField::from_field(&self.0.eject_value()) { 72 Ok(identifier) => identifier, 73 Err(error) => A::halt(format!("Failed to convert an identifier to a string: {error}")), 74 } 75 } 76 } 77 78 impl<A: Alpha> Parser for Identifier<A> { 79 /// Parses a UTF-8 string into an identifier. 80 #[inline] 81 fn parse(string: &str) -> ParserResult<Self> { 82 // Parse the identifier from the string. 83 let (string, identifier) = console::Identifier::parse(string)?; 84 85 Ok((string, Identifier::constant(identifier))) 86 } 87 } 88 89 impl<A: Alpha> FromStr for Identifier<A> { 90 type Err = Error; 91 92 /// Parses a UTF-8 string into an identifier. 93 #[inline] 94 fn from_str(string: &str) -> Result<Self> { 95 match Self::parse(string) { 96 Ok((remainder, object)) => { 97 // Ensure the remainder is empty. 98 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 99 // Return the object. 100 Ok(object) 101 } 102 Err(error) => bail!("Failed to parse string. {error}"), 103 } 104 } 105 } 106 107 impl<A: Alpha> Debug for Identifier<A> { 108 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 109 Display::fmt(self, f) 110 } 111 } 112 113 impl<A: Alpha> Display for Identifier<A> { 114 /// Prints the identifier as a string. 115 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 116 write!(f, "{}", self.eject_value()) 117 } 118 } 119 120 impl<A: Alpha> Eq for Identifier<A> {} 121 122 impl<A: Alpha> PartialEq for Identifier<A> { 123 /// Implements the `Eq` trait for the identifier. 124 fn eq(&self, other: &Self) -> bool { 125 self.0.eject_value() == other.0.eject_value() 126 } 127 } 128 129 impl<A: Alpha> core::hash::Hash for Identifier<A> { 130 /// Implements the `Hash` trait for the identifier. 131 fn hash<H: core::hash::Hasher>(&self, state: &mut H) { 132 self.0.eject_value().hash(state); 133 } 134 } 135 136 impl<A: Alpha> From<Identifier<A>> for LinearCombination<A::BaseField> { 137 /// Note: Identifier is always `Mode::Constant`. 138 fn from(identifier: Identifier<A>) -> Self { 139 From::from(&identifier) 140 } 141 } 142 143 impl<A: Alpha> From<&Identifier<A>> for LinearCombination<A::BaseField> { 144 /// Note: Identifier is always `Mode::Constant`. 145 fn from(identifier: &Identifier<A>) -> Self { 146 LinearCombination::from(&identifier.0) 147 } 148 } 149 150 #[cfg(test)] 151 pub(crate) mod tests { 152 use super::*; 153 use crate::Circuit; 154 use console::{Rng, TestRng}; 155 156 use anyhow::{Result, bail}; 157 use core::str::FromStr; 158 use rand::distributions::Alphanumeric; 159 160 /// Samples a random identifier. 161 pub(crate) fn sample_console_identifier<A: Alpha>() -> Result<console::Identifier<A::Network>> { 162 // Sample a random fixed-length alphanumeric string, that always starts with an alphabetic character. 163 let string = sample_console_identifier_as_string::<A>()?; 164 // Return the identifier. 165 console::Identifier::from_str(&string) 166 } 167 168 /// Samples a random identifier as a string. 169 pub(crate) fn sample_console_identifier_as_string<A: Alpha>() -> Result<String> { 170 // Initialize a test RNG. 171 let rng = &mut TestRng::default(); 172 // Sample a random fixed-length alphanumeric string, that always starts with an alphabetic character. 173 let string = "a".to_string() 174 + &rng 175 .sample_iter(&Alphanumeric) 176 .take(A::BaseField::size_in_data_bits() / (8 * 2)) 177 .map(char::from) 178 .collect::<String>(); 179 // Ensure identifier fits within the data capacity of the base field. 180 let max_bytes = A::BaseField::size_in_data_bits() / 8; // Note: This intentionally rounds down. 181 match string.len() <= max_bytes { 182 // Return the identifier. 183 true => Ok(string), 184 false => bail!("Identifier exceeds the maximum capacity allowed"), 185 } 186 } 187 188 /// Samples a random identifier as a string. 189 pub(crate) fn sample_lowercase_console_identifier_as_string<A: Alpha>() -> Result<String> { 190 // Sample a random identifier. 191 let string = sample_console_identifier_as_string::<A>()?; 192 // Return the identifier as lowercase. 193 Ok(string.to_lowercase()) 194 } 195 196 #[test] 197 fn test_identifier_parse() -> Result<()> { 198 let candidate = Identifier::<Circuit>::parse("foo_bar").unwrap(); 199 assert_eq!("", candidate.0); 200 assert_eq!(Identifier::<Circuit>::constant("foo_bar".try_into()?).eject(), candidate.1.eject()); 201 Ok(()) 202 } 203 204 #[test] 205 fn test_identifier_parse_fails() -> Result<()> { 206 // Must be alphanumeric or underscore. 207 let identifier = Identifier::<Circuit>::parse("foo_bar~baz").unwrap(); 208 assert_eq!(("~baz", Identifier::<Circuit>::from_str("foo_bar")?.eject()), (identifier.0, identifier.1.eject())); 209 let identifier = Identifier::<Circuit>::parse("foo_bar-baz").unwrap(); 210 assert_eq!(("-baz", Identifier::<Circuit>::from_str("foo_bar")?.eject()), (identifier.0, identifier.1.eject())); 211 212 // Must not be solely underscores. 213 assert!(Identifier::<Circuit>::parse("_").is_err()); 214 assert!(Identifier::<Circuit>::parse("__").is_err()); 215 assert!(Identifier::<Circuit>::parse("___").is_err()); 216 assert!(Identifier::<Circuit>::parse("____").is_err()); 217 218 // Must not start with a number. 219 assert!(Identifier::<Circuit>::parse("1").is_err()); 220 assert!(Identifier::<Circuit>::parse("2").is_err()); 221 assert!(Identifier::<Circuit>::parse("3").is_err()); 222 assert!(Identifier::<Circuit>::parse("1foo").is_err()); 223 assert!(Identifier::<Circuit>::parse("12").is_err()); 224 assert!(Identifier::<Circuit>::parse("111").is_err()); 225 226 // Must fit within the data capacity of a base field element. 227 let identifier = 228 Identifier::<Circuit>::parse("foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy"); 229 assert!(identifier.is_err()); 230 Ok(()) 231 } 232 233 #[test] 234 fn test_identifier_display() -> Result<()> { 235 let identifier = Identifier::<Circuit>::from_str("foo_bar")?; 236 assert_eq!("foo_bar", format!("{identifier}")); 237 Ok(()) 238 } 239 240 #[test] 241 fn test_identifier_bits() -> Result<()> { 242 let identifier = Identifier::<Circuit>::from_str("foo_bar")?; 243 assert_eq!( 244 identifier.to_bits_le().eject(), 245 Identifier::from_bits_le(&identifier.to_bits_le()).to_bits_le().eject() 246 ); 247 assert_eq!( 248 identifier.to_bits_be().eject(), 249 Identifier::from_bits_be(&identifier.to_bits_be()).to_bits_be().eject() 250 ); 251 Ok(()) 252 } 253 }