snarkvm_circuit_types_field/
lib.rs1#![forbid(unsafe_code)]
17#![allow(clippy::too_many_arguments)]
18#![cfg_attr(test, allow(clippy::assertions_on_result_states))]
19
20mod helpers;
21
22pub mod add;
23pub mod compare;
24pub mod div;
25pub mod div_unchecked;
26pub mod double;
27pub mod equal;
28pub mod inverse;
29pub mod mul;
30pub mod neg;
31pub mod pow;
32pub mod square;
33pub mod square_root;
34pub mod sub;
35pub mod ternary;
36
37#[cfg(test)]
38use console::{TestRng, Uniform};
39#[cfg(test)]
40use snarkvm_circuit_environment::{assert_count, assert_output_mode, assert_scope, count, output_mode};
41
42use snarkvm_circuit_environment::prelude::*;
43use snarkvm_circuit_types_boolean::Boolean;
44
45#[derive(Clone)]
46pub struct Field<E: Environment> {
47 linear_combination: LinearCombination<E::BaseField>,
49 bits_le: OnceCell<Vec<Boolean<E>>>,
52}
53
54impl<E: Environment> FieldTrait for Field<E> {}
55
56impl<E: Environment> Default for Field<E> {
57 fn default() -> Self {
59 Self::zero()
60 }
61}
62
63#[cfg(feature = "console")]
64impl<E: Environment> Inject for Field<E> {
65 type Primitive = console::Field<E::Network>;
66
67 fn new(mode: Mode, field: Self::Primitive) -> Self {
69 Self { linear_combination: E::new_variable(mode, *field).into(), bits_le: Default::default() }
70 }
71}
72
73#[cfg(feature = "console")]
74impl<E: Environment> Eject for Field<E> {
75 type Primitive = console::Field<E::Network>;
76
77 fn eject_mode(&self) -> Mode {
79 self.linear_combination.mode()
80 }
81
82 fn eject_value(&self) -> Self::Primitive {
84 console::Field::new(self.linear_combination.value())
85 }
86}
87
88#[cfg(feature = "console")]
89impl<E: Environment> Parser for Field<E> {
90 #[inline]
92 fn parse(string: &str) -> ParserResult<Self> {
93 let (string, field) = console::Field::parse(string)?;
95 let (string, mode) = opt(pair(tag("."), Mode::parse))(string)?;
97
98 match mode {
99 Some((_, mode)) => Ok((string, Field::new(mode, field))),
100 None => Ok((string, Field::new(Mode::Constant, field))),
101 }
102 }
103}
104
105#[cfg(feature = "console")]
106impl<E: Environment> FromStr for Field<E> {
107 type Err = Error;
108
109 #[inline]
111 fn from_str(string: &str) -> Result<Self> {
112 match Self::parse(string) {
113 Ok((remainder, object)) => {
114 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
116 Ok(object)
118 }
119 Err(error) => bail!("Failed to parse string. {error}"),
120 }
121 }
122}
123
124#[cfg(feature = "console")]
125impl<E: Environment> TypeName for Field<E> {
126 #[inline]
128 fn type_name() -> &'static str {
129 console::Field::<E::Network>::type_name()
130 }
131}
132
133#[cfg(feature = "console")]
134impl<E: Environment> Debug for Field<E> {
135 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136 Display::fmt(self, f)
137 }
138}
139
140#[cfg(feature = "console")]
141impl<E: Environment> Display for Field<E> {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 write!(f, "{}.{}", self.eject_value(), self.eject_mode())
144 }
145}
146
147impl<E: Environment> From<LinearCombination<E::BaseField>> for Field<E> {
148 fn from(linear_combination: LinearCombination<E::BaseField>) -> Self {
149 Self { linear_combination, bits_le: Default::default() }
150 }
151}
152
153impl<E: Environment> From<&LinearCombination<E::BaseField>> for Field<E> {
154 fn from(linear_combination: &LinearCombination<E::BaseField>) -> Self {
155 From::from(linear_combination.clone())
156 }
157}
158
159impl<E: Environment> From<Field<E>> for LinearCombination<E::BaseField> {
160 fn from(field: Field<E>) -> Self {
161 From::from(&field)
162 }
163}
164
165impl<E: Environment> From<&Field<E>> for LinearCombination<E::BaseField> {
166 fn from(field: &Field<E>) -> Self {
167 field.linear_combination.clone()
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174 use snarkvm_circuit_environment::Circuit;
175
176 const ITERATIONS: u64 = 10_000;
177
178 fn check_display(mode: Mode, element: console::Field<<Circuit as Environment>::Network>) -> Result<()> {
181 let candidate = Field::<Circuit>::new(mode, element);
182 assert_eq!(format!("{element}.{mode}"), format!("{candidate}"));
183
184 let candidate_recovered = Field::<Circuit>::from_str(&format!("{candidate}"))?;
185 assert_eq!(candidate.eject_value(), candidate_recovered.eject_value());
186 Ok(())
187 }
188
189 #[test]
190 fn test_display() -> Result<()> {
191 let mut rng = TestRng::default();
192
193 for _ in 0..ITERATIONS {
194 let element = Uniform::rand(&mut rng);
195
196 check_display(Mode::Constant, element)?;
198 check_display(Mode::Public, element)?;
200 check_display(Mode::Private, element)?;
202 }
203 Ok(())
204 }
205
206 #[test]
207 fn test_display_zero() {
208 let zero = console::Field::<<Circuit as Environment>::Network>::zero();
209
210 let candidate = Field::<Circuit>::new(Mode::Constant, zero);
212 assert_eq!("0field.constant", &format!("{candidate}"));
213
214 let candidate = Field::<Circuit>::new(Mode::Public, zero);
216 assert_eq!("0field.public", &format!("{candidate}"));
217
218 let candidate = Field::<Circuit>::new(Mode::Private, zero);
220 assert_eq!("0field.private", &format!("{candidate}"));
221 }
222
223 #[test]
224 fn test_display_one() {
225 let one = console::Field::<<Circuit as Environment>::Network>::one();
226
227 let candidate = Field::<Circuit>::new(Mode::Constant, one);
229 assert_eq!("1field.constant", &format!("{candidate}"));
230
231 let candidate = Field::<Circuit>::new(Mode::Public, one);
233 assert_eq!("1field.public", &format!("{candidate}"));
234
235 let candidate = Field::<Circuit>::new(Mode::Private, one);
237 assert_eq!("1field.private", &format!("{candidate}"));
238 }
239
240 #[test]
241 fn test_display_two() {
242 let one = console::Field::<<Circuit as Environment>::Network>::one();
243 let two = one + one;
244
245 let candidate = Field::<Circuit>::new(Mode::Constant, two);
247 assert_eq!("2field.constant", &format!("{candidate}"));
248
249 let candidate = Field::<Circuit>::new(Mode::Public, two);
251 assert_eq!("2field.public", &format!("{candidate}"));
252
253 let candidate = Field::<Circuit>::new(Mode::Private, two);
255 assert_eq!("2field.private", &format!("{candidate}"));
256 }
257
258 #[test]
259 fn test_parser() {
260 type Primitive = console::Field<<Circuit as Environment>::Network>;
261
262 let (_, candidate) = Field::<Circuit>::parse("5field").unwrap();
265 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
266 assert!(candidate.is_constant());
267
268 let (_, candidate) = Field::<Circuit>::parse("5_field").unwrap();
269 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
270 assert!(candidate.is_constant());
271
272 let (_, candidate) = Field::<Circuit>::parse("1_5_field").unwrap();
273 assert_eq!(Primitive::from_str("15field").unwrap(), candidate.eject_value());
274 assert!(candidate.is_constant());
275
276 let (_, candidate) = Field::<Circuit>::parse("5field.constant").unwrap();
277 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
278 assert!(candidate.is_constant());
279
280 let (_, candidate) = Field::<Circuit>::parse("5_field.constant").unwrap();
281 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
282 assert!(candidate.is_constant());
283
284 let (_, candidate) = Field::<Circuit>::parse("1_5_field.constant").unwrap();
285 assert_eq!(Primitive::from_str("15field").unwrap(), candidate.eject_value());
286 assert!(candidate.is_constant());
287
288 let (_, candidate) = Field::<Circuit>::parse("5field.public").unwrap();
291 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
292 assert!(candidate.is_public());
293
294 let (_, candidate) = Field::<Circuit>::parse("5_field.public").unwrap();
295 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
296 assert!(candidate.is_public());
297
298 let (_, candidate) = Field::<Circuit>::parse("1_5_field.public").unwrap();
299 assert_eq!(Primitive::from_str("15field").unwrap(), candidate.eject_value());
300 assert!(candidate.is_public());
301
302 let (_, candidate) = Field::<Circuit>::parse("5field.private").unwrap();
305 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
306 assert!(candidate.is_private());
307
308 let (_, candidate) = Field::<Circuit>::parse("5_field.private").unwrap();
309 assert_eq!(Primitive::from_str("5field").unwrap(), candidate.eject_value());
310 assert!(candidate.is_private());
311
312 let (_, candidate) = Field::<Circuit>::parse("1_5_field.private").unwrap();
313 assert_eq!(Primitive::from_str("15field").unwrap(), candidate.eject_value());
314 assert!(candidate.is_private());
315
316 let mut rng = TestRng::default();
319
320 for mode in [Mode::Constant, Mode::Public, Mode::Private] {
321 for _ in 0..ITERATIONS {
322 let value = Uniform::rand(&mut rng);
323 let expected = Field::<Circuit>::new(mode, value);
324
325 let (_, candidate) = Field::<Circuit>::parse(&format!("{expected}")).unwrap();
326 assert_eq!(expected.eject_value(), candidate.eject_value());
327 assert_eq!(mode, candidate.eject_mode());
328 }
329 }
330 }
331}