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_utilities::ToBits as TB;
29
30#[derive(Clone)]
40pub struct Identifier<A: Aleo>(Field<A>, u8); #[cfg(feature = "console")]
43impl<A: Aleo> Inject for Identifier<A> {
44 type Primitive = console::Identifier<A::Network>;
45
46 fn new(_: Mode, identifier: Self::Primitive) -> Self {
49 let identifier = identifier.to_string();
51
52 let field = Field::from_bits_le(&Vec::<Boolean<_>>::constant(identifier.to_bits_le()));
55
56 Self(field, identifier.len() as u8)
58 }
59}
60
61#[cfg(feature = "console")]
62impl<A: Aleo> Eject for Identifier<A> {
63 type Primitive = console::Identifier<A::Network>;
64
65 fn eject_mode(&self) -> Mode {
67 debug_assert!(self.0.eject_mode() == Mode::Constant, "Identifier::eject_mode - Mode must be 'Constant'");
68 Mode::Constant
69 }
70
71 fn eject_value(&self) -> Self::Primitive {
73 match console::FromField::from_field(&self.0.eject_value()) {
74 Ok(identifier) => identifier,
75 Err(error) => A::halt(format!("Failed to convert an identifier to a string: {error}")),
76 }
77 }
78}
79
80#[cfg(feature = "console")]
81impl<A: Aleo> Parser for Identifier<A> {
82 #[inline]
84 fn parse(string: &str) -> ParserResult<Self> {
85 let (string, identifier) = console::Identifier::parse(string)?;
87
88 Ok((string, Identifier::constant(identifier)))
89 }
90}
91
92#[cfg(feature = "console")]
93impl<A: Aleo> FromStr for Identifier<A> {
94 type Err = Error;
95
96 #[inline]
98 fn from_str(string: &str) -> Result<Self> {
99 match Self::parse(string) {
100 Ok((remainder, object)) => {
101 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
103 Ok(object)
105 }
106 Err(error) => bail!("Failed to parse string. {error}"),
107 }
108 }
109}
110
111#[cfg(feature = "console")]
112impl<A: Aleo> Debug for Identifier<A> {
113 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
114 Display::fmt(self, f)
115 }
116}
117
118#[cfg(feature = "console")]
119impl<A: Aleo> Display for Identifier<A> {
120 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
122 write!(f, "{}", self.eject_value())
123 }
124}
125
126impl<A: Aleo> Eq for Identifier<A> {}
127
128impl<A: Aleo> PartialEq for Identifier<A> {
129 fn eq(&self, other: &Self) -> bool {
131 self.0.eject_value() == other.0.eject_value()
132 }
133}
134
135impl<A: Aleo> core::hash::Hash for Identifier<A> {
136 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
138 self.0.eject_value().hash(state);
139 }
140}
141
142impl<A: Aleo> From<Identifier<A>> for LinearCombination<A::BaseField> {
143 fn from(identifier: Identifier<A>) -> Self {
145 From::from(&identifier)
146 }
147}
148
149impl<A: Aleo> From<&Identifier<A>> for LinearCombination<A::BaseField> {
150 fn from(identifier: &Identifier<A>) -> Self {
152 LinearCombination::from(&identifier.0)
153 }
154}
155
156#[cfg(all(test, feature = "console"))]
157pub(crate) mod tests {
158 use super::*;
159 use crate::Circuit;
160 use console::{Rng, TestRng};
161
162 use anyhow::{Result, bail};
163 use core::str::FromStr;
164 use rand::distributions::Alphanumeric;
165
166 pub(crate) fn sample_console_identifier<A: Aleo>() -> Result<console::Identifier<A::Network>> {
168 let string = sample_console_identifier_as_string::<A>()?;
170 console::Identifier::from_str(&string)
172 }
173
174 pub(crate) fn sample_console_identifier_as_string<A: Aleo>() -> Result<String> {
176 let rng = &mut TestRng::default();
178 let string = "a".to_string()
180 + &rng
181 .sample_iter(&Alphanumeric)
182 .take(A::BaseField::size_in_data_bits() / (8 * 2))
183 .map(char::from)
184 .collect::<String>();
185 let max_bytes = A::BaseField::size_in_data_bits() / 8; match string.len() <= max_bytes {
188 true => Ok(string),
190 false => bail!("Identifier exceeds the maximum capacity allowed"),
191 }
192 }
193
194 pub(crate) fn sample_lowercase_console_identifier_as_string<A: Aleo>() -> Result<String> {
196 let string = sample_console_identifier_as_string::<A>()?;
198 Ok(string.to_lowercase())
200 }
201
202 #[test]
203 fn test_identifier_parse() -> Result<()> {
204 let candidate = Identifier::<Circuit>::parse("foo_bar").unwrap();
205 assert_eq!("", candidate.0);
206 assert_eq!(Identifier::<Circuit>::constant("foo_bar".try_into()?).eject(), candidate.1.eject());
207 Ok(())
208 }
209
210 #[test]
211 fn test_identifier_parse_fails() -> Result<()> {
212 let identifier = Identifier::<Circuit>::parse("foo_bar~baz").unwrap();
214 assert_eq!(("~baz", Identifier::<Circuit>::from_str("foo_bar")?.eject()), (identifier.0, identifier.1.eject()));
215 let identifier = Identifier::<Circuit>::parse("foo_bar-baz").unwrap();
216 assert_eq!(("-baz", Identifier::<Circuit>::from_str("foo_bar")?.eject()), (identifier.0, identifier.1.eject()));
217
218 assert!(Identifier::<Circuit>::parse("_").is_err());
220 assert!(Identifier::<Circuit>::parse("__").is_err());
221 assert!(Identifier::<Circuit>::parse("___").is_err());
222 assert!(Identifier::<Circuit>::parse("____").is_err());
223
224 assert!(Identifier::<Circuit>::parse("1").is_err());
226 assert!(Identifier::<Circuit>::parse("2").is_err());
227 assert!(Identifier::<Circuit>::parse("3").is_err());
228 assert!(Identifier::<Circuit>::parse("1foo").is_err());
229 assert!(Identifier::<Circuit>::parse("12").is_err());
230 assert!(Identifier::<Circuit>::parse("111").is_err());
231
232 let identifier =
234 Identifier::<Circuit>::parse("foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy");
235 assert!(identifier.is_err());
236 Ok(())
237 }
238
239 #[test]
240 fn test_identifier_display() -> Result<()> {
241 let identifier = Identifier::<Circuit>::from_str("foo_bar")?;
242 assert_eq!("foo_bar", format!("{identifier}"));
243 Ok(())
244 }
245
246 #[test]
247 fn test_identifier_bits() -> Result<()> {
248 let identifier = Identifier::<Circuit>::from_str("foo_bar")?;
249 assert_eq!(
250 identifier.to_bits_le().eject(),
251 Identifier::from_bits_le(&identifier.to_bits_le()).to_bits_le().eject()
252 );
253 assert_eq!(
254 identifier.to_bits_be().eject(),
255 Identifier::from_bits_be(&identifier.to_bits_be()).to_bits_be().eject()
256 );
257 Ok(())
258 }
259}