snarkvm_console_program/data/literal/cast_lossy/
field.rs1use super::*;
17
18impl<E: Environment> CastLossy<Address<E>> for Field<E> {
19 #[inline]
25 fn cast_lossy(&self) -> Address<E> {
26 let group: Group<E> = self.cast_lossy();
28 Address::new(group)
30 }
31}
32
33impl<E: Environment> CastLossy<Boolean<E>> for Field<E> {
34 #[inline]
37 fn cast_lossy(&self) -> Boolean<E> {
38 let bits_le = self.to_bits_le();
39 debug_assert!(!bits_le.is_empty(), "An integer must have at least one bit");
40 Boolean::new(bits_le[0])
41 }
42}
43
44impl<E: Environment> CastLossy<Field<E>> for Field<E> {
45 #[inline]
48 fn cast_lossy(&self) -> Field<E> {
49 *self
50 }
51}
52
53impl<E: Environment> CastLossy<Group<E>> for Field<E> {
54 #[inline]
63 fn cast_lossy(&self) -> Group<E> {
64 match Group::from_x_coordinate(*self) {
65 Ok(group) => group,
66 Err(_) => match self.is_one() {
67 true => Group::generator(),
68 false => {
69 let result = Elligator2::encode(self);
71 debug_assert!(result.is_ok(), "Elligator-2 should never fail to encode a field element");
72 result.unwrap().0
73 }
74 },
75 }
76 }
77}
78
79impl<E: Environment, I: IntegerType> CastLossy<Integer<E, I>> for Field<E> {
80 #[inline]
83 fn cast_lossy(&self) -> Integer<E, I> {
84 Integer::from_field_lossy(self)
85 }
86}
87
88impl<E: Environment> CastLossy<Scalar<E>> for Field<E> {
89 #[inline]
92 fn cast_lossy(&self) -> Scalar<E> {
93 Scalar::from_field_lossy(self)
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use snarkvm_console_network::Console;
101
102 type CurrentEnvironment = Console;
103
104 const ITERATIONS: u64 = 10_000;
105
106 #[test]
107 fn test_field_to_address() {
108 let rng = &mut TestRng::default();
109
110 let field = Field::<CurrentEnvironment>::one();
111 let address: Address<CurrentEnvironment> = field.cast_lossy();
112 assert_eq!(address, Address::new(Group::generator()));
113 assert_eq!(address.to_group(), &Group::generator());
114
115 let field = Field::<CurrentEnvironment>::zero();
116 let address: Address<CurrentEnvironment> = field.cast_lossy();
117 assert_eq!(address, Address::zero());
118 assert_eq!(address.to_group(), &Group::zero());
119
120 for _ in 0..ITERATIONS {
121 let field = Field::<CurrentEnvironment>::rand(rng);
123 let candidate: Address<CurrentEnvironment> = field.cast_lossy();
125 let expected: Group<CurrentEnvironment> = field.cast_lossy();
127 assert_eq!(Address::new(expected), candidate);
128 }
129 }
130
131 #[test]
132 fn test_field_to_boolean() {
133 let rng = &mut TestRng::default();
134
135 let field = Field::<CurrentEnvironment>::one();
136 let boolean: Boolean<CurrentEnvironment> = field.cast_lossy();
137 assert_eq!(boolean, Boolean::new(true));
138
139 let field = Field::<CurrentEnvironment>::zero();
140 let boolean: Boolean<CurrentEnvironment> = field.cast_lossy();
141 assert_eq!(boolean, Boolean::new(false));
142
143 for _ in 0..ITERATIONS {
144 let field = Field::<CurrentEnvironment>::rand(rng);
146 let candidate: Boolean<CurrentEnvironment> = field.cast_lossy();
148 let expected = Boolean::new(field.to_bits_be().pop().unwrap());
150 assert_eq!(expected, candidate);
151 }
152 }
153
154 #[test]
155 fn test_field_to_field() {
156 let rng = &mut TestRng::default();
157
158 for _ in 0..ITERATIONS {
159 let field = Field::<CurrentEnvironment>::rand(rng);
161 let candidate: Field<CurrentEnvironment> = field.cast_lossy();
163 assert_eq!(field, candidate);
164 }
165 }
166
167 #[test]
168 fn test_field_to_group() {
169 let rng = &mut TestRng::default();
170
171 let field = Field::<CurrentEnvironment>::one();
172 let group: Group<CurrentEnvironment> = field.cast_lossy();
173 assert_eq!(group, Group::generator());
174
175 let field = Field::<CurrentEnvironment>::zero();
176 let group: Group<CurrentEnvironment> = field.cast_lossy();
177 assert_eq!(group, Group::zero());
178
179 for _ in 0..ITERATIONS {
180 let field = Field::<CurrentEnvironment>::rand(rng);
182 let candidate: Group<CurrentEnvironment> = field.cast_lossy();
184 let expected: Address<CurrentEnvironment> = field.cast_lossy();
186 assert_eq!(expected.to_group(), &candidate);
187 }
188 }
189
190 #[test]
191 fn test_field_to_scalar() {
192 let rng = &mut TestRng::default();
193
194 let field = Field::<CurrentEnvironment>::one();
195 let scalar: Scalar<CurrentEnvironment> = field.cast_lossy();
196 assert_eq!(scalar, Scalar::one());
197
198 let field = Field::<CurrentEnvironment>::zero();
199 let scalar: Scalar<CurrentEnvironment> = field.cast_lossy();
200 assert_eq!(scalar, Scalar::zero());
201
202 for _ in 0..ITERATIONS {
203 let field = Field::<CurrentEnvironment>::rand(rng);
205 let candidate: Scalar<CurrentEnvironment> = field.cast_lossy();
207 assert_eq!(Scalar::from_field_lossy(&field), candidate);
208 }
209 }
210
211 macro_rules! check_field_to_integer {
212 ($type:ty) => {
213 let rng = &mut TestRng::default();
214
215 let field = Field::<CurrentEnvironment>::one();
216 let integer: $type = field.cast_lossy();
217 assert_eq!(integer, <$type>::one());
218
219 let field = Field::<CurrentEnvironment>::zero();
220 let integer: $type = field.cast_lossy();
221 assert_eq!(integer, <$type>::zero());
222
223 for _ in 0..ITERATIONS {
224 let field = Field::<CurrentEnvironment>::rand(rng);
226 let candidate: $type = field.cast_lossy();
228 assert_eq!(<$type>::from_field_lossy(&field), candidate);
229 }
230 };
231 }
232
233 #[test]
234 fn test_field_to_i8() {
235 check_field_to_integer!(I8<CurrentEnvironment>);
236 }
237
238 #[test]
239 fn test_field_to_i16() {
240 check_field_to_integer!(I16<CurrentEnvironment>);
241 }
242
243 #[test]
244 fn test_field_to_i32() {
245 check_field_to_integer!(I32<CurrentEnvironment>);
246 }
247
248 #[test]
249 fn test_field_to_i64() {
250 check_field_to_integer!(I64<CurrentEnvironment>);
251 }
252
253 #[test]
254 fn test_field_to_i128() {
255 check_field_to_integer!(I128<CurrentEnvironment>);
256 }
257
258 #[test]
259 fn test_field_to_u8() {
260 check_field_to_integer!(U8<CurrentEnvironment>);
261 }
262
263 #[test]
264 fn test_field_to_u16() {
265 check_field_to_integer!(U16<CurrentEnvironment>);
266 }
267
268 #[test]
269 fn test_field_to_u32() {
270 check_field_to_integer!(U32<CurrentEnvironment>);
271 }
272
273 #[test]
274 fn test_field_to_u64() {
275 check_field_to_integer!(U64<CurrentEnvironment>);
276 }
277
278 #[test]
279 fn test_field_to_u128() {
280 check_field_to_integer!(U128<CurrentEnvironment>);
281 }
282}