snarkvm_circuit_program/data/identifier/
mod.rs1#[cfg(test)]
17use snarkvm_circuit_types::environment::assert_scope;
18
19mod equal;
20mod from_bits;
21mod from_field;
22mod size_in_bits;
23mod to_bits;
24mod to_field;
25
26use snarkvm_circuit_network::Aleo;
27use snarkvm_circuit_types::{Boolean, Field, U8, environment::prelude::*};
28use snarkvm_console_program::ToField as TF;
29use snarkvm_utilities::ToBits as TB;
30
31#[derive(Clone)]
41pub struct Identifier<A: Aleo>(Field<A>, u8); impl<A: Aleo> Identifier<A> {
44 pub fn constant(identifier: console::Identifier<A::Network>) -> Self {
46 let identifier_string = identifier.to_string();
51
52 let field = Field::from_bits_le(&Vec::<Boolean<_>>::constant(identifier_string.to_bits_le()));
55
56 Self(field, identifier_string.len() as u8)
58 }
59
60 pub fn public(identifier: console::Identifier<A::Network>) -> Self {
65 let identifier_string = identifier.to_string();
67
68 let field = match identifier.to_field() {
70 Ok(field) => Field::new(Mode::Public, field),
71 Err(error) => A::halt(format!("Failed to convert an identifier to a field: {error}")),
72 };
73
74 Self(field, identifier_string.len() as u8)
75 }
76}
77
78impl<A: Aleo> Eject for Identifier<A> {
79 type Primitive = console::Identifier<A::Network>;
80
81 fn eject_mode(&self) -> Mode {
83 let mode = self.0.eject_mode();
85
86 debug_assert!(mode != Mode::Private, "Identifier::eject_mode - Mode cannot be 'Private'");
87 mode
88 }
89
90 fn eject_value(&self) -> Self::Primitive {
92 match console::FromField::from_field(&self.0.eject_value()) {
93 Ok(identifier) => identifier,
94 Err(error) => A::halt(format!("Failed to convert an identifier to a string: {error}")),
95 }
96 }
97}
98
99impl<A: Aleo> Parser for Identifier<A> {
100 #[inline]
102 fn parse(string: &str) -> ParserResult<Self> {
103 let (string, identifier) = console::Identifier::parse(string)?;
105
106 Ok((string, Identifier::constant(identifier)))
107 }
108}
109
110impl<A: Aleo> FromStr for Identifier<A> {
111 type Err = Error;
112
113 #[inline]
115 fn from_str(string: &str) -> Result<Self> {
116 match Self::parse(string) {
117 Ok((remainder, object)) => {
118 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
120 Ok(object)
122 }
123 Err(error) => bail!("Failed to parse string. {error}"),
124 }
125 }
126}
127
128impl<A: Aleo> Debug for Identifier<A> {
129 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
130 Display::fmt(self, f)
131 }
132}
133
134impl<A: Aleo> Display for Identifier<A> {
135 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
137 write!(f, "{}", self.eject_value())
138 }
139}
140
141impl<A: Aleo> Eq for Identifier<A> {}
142
143impl<A: Aleo> PartialEq for Identifier<A> {
144 fn eq(&self, other: &Self) -> bool {
146 self.0.eject_value() == other.0.eject_value()
147 }
148}
149
150impl<A: Aleo> core::hash::Hash for Identifier<A> {
151 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
153 self.0.eject_value().hash(state);
154 }
155}
156
157impl<A: Aleo> From<Identifier<A>> for LinearCombination<A::BaseField> {
158 fn from(identifier: Identifier<A>) -> Self {
160 From::from(&identifier)
161 }
162}
163
164impl<A: Aleo> From<&Identifier<A>> for LinearCombination<A::BaseField> {
165 fn from(identifier: &Identifier<A>) -> Self {
167 LinearCombination::from(&identifier.0)
168 }
169}
170
171#[cfg(test)]
172pub(crate) mod tests {
173 use super::*;
174 use crate::Circuit;
175 use console::{Rng, TestRng};
176
177 use anyhow::{Result, bail};
178 use core::str::FromStr;
179 use rand::distributions::Alphanumeric;
180
181 pub(crate) fn sample_console_identifier<A: Aleo>() -> Result<console::Identifier<A::Network>> {
183 let string = sample_console_identifier_as_string::<A>()?;
185 console::Identifier::from_str(&string)
187 }
188
189 pub(crate) fn sample_console_identifier_as_string<A: Aleo>() -> Result<String> {
191 let rng = &mut TestRng::default();
193 let string = "a".to_string()
195 + &rng
196 .sample_iter(&Alphanumeric)
197 .take(A::BaseField::size_in_data_bits() / (8 * 2))
198 .map(char::from)
199 .collect::<String>();
200 let max_bytes = A::BaseField::size_in_data_bits() / 8; match string.len() <= max_bytes {
203 true => Ok(string),
205 false => bail!("Identifier exceeds the maximum capacity allowed"),
206 }
207 }
208
209 pub(crate) fn sample_lowercase_console_identifier_as_string<A: Aleo>() -> Result<String> {
211 let string = sample_console_identifier_as_string::<A>()?;
213 Ok(string.to_lowercase())
215 }
216
217 #[test]
218 fn test_identifier_parse() -> Result<()> {
219 let candidate = Identifier::<Circuit>::parse("foo_bar").unwrap();
220 assert_eq!("", candidate.0);
221 assert_eq!(Identifier::<Circuit>::constant("foo_bar".try_into()?).eject(), candidate.1.eject());
222 Ok(())
223 }
224
225 #[test]
226 fn test_identifier_parse_fails() -> Result<()> {
227 let identifier = Identifier::<Circuit>::parse("foo_bar~baz").unwrap();
229 assert_eq!(("~baz", Identifier::<Circuit>::from_str("foo_bar")?.eject()), (identifier.0, identifier.1.eject()));
230 let identifier = Identifier::<Circuit>::parse("foo_bar-baz").unwrap();
231 assert_eq!(("-baz", Identifier::<Circuit>::from_str("foo_bar")?.eject()), (identifier.0, identifier.1.eject()));
232
233 assert!(Identifier::<Circuit>::parse("_").is_err());
235 assert!(Identifier::<Circuit>::parse("__").is_err());
236 assert!(Identifier::<Circuit>::parse("___").is_err());
237 assert!(Identifier::<Circuit>::parse("____").is_err());
238
239 assert!(Identifier::<Circuit>::parse("1").is_err());
241 assert!(Identifier::<Circuit>::parse("2").is_err());
242 assert!(Identifier::<Circuit>::parse("3").is_err());
243 assert!(Identifier::<Circuit>::parse("1foo").is_err());
244 assert!(Identifier::<Circuit>::parse("12").is_err());
245 assert!(Identifier::<Circuit>::parse("111").is_err());
246
247 let identifier =
249 Identifier::<Circuit>::parse("foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy");
250 assert!(identifier.is_err());
251 Ok(())
252 }
253
254 #[test]
255 fn test_identifier_display() -> Result<()> {
256 let identifier = Identifier::<Circuit>::from_str("foo_bar")?;
257 assert_eq!("foo_bar", format!("{identifier}"));
258 Ok(())
259 }
260
261 #[test]
262 fn test_identifier_bits() -> Result<()> {
263 let identifier = Identifier::<Circuit>::from_str("foo_bar")?;
264 assert_eq!(
265 identifier.to_bits_le().eject(),
266 Identifier::from_bits_le(&identifier.to_bits_le()).to_bits_le().eject()
267 );
268 assert_eq!(
269 identifier.to_bits_be().eject(),
270 Identifier::from_bits_be(&identifier.to_bits_be()).to_bits_be().eject()
271 );
272 Ok(())
273 }
274}