Skip to main content

snarkvm_circuit_program/data/literal/cast/
field.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM 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
16use super::*;
17
18impl<E: Environment> Cast<Address<E>> for Field<E> {
19    /// Casts a `Field` to an `Address`.
20    ///
21    /// This operation attempts to recover the group element from the field element, and then
22    /// constructs an address from the group element.
23    ///
24    /// To cast arbitrary field elements to addresses, use `Field::cast_lossy`.
25    #[inline]
26    fn cast(&self) -> Address<E> {
27        Address::from_field(self.clone())
28    }
29}
30
31impl<E: Environment> Cast<Boolean<E>> for Field<E> {
32    /// Casts a `Field` to a `Boolean`, if the field is zero or one.
33    ///
34    /// To cast arbitrary field elements to booleans, use `Field::cast_lossy`.
35    #[inline]
36    fn cast(&self) -> Boolean<E> {
37        let is_one = self.is_one();
38        E::assert(self.is_zero().bitor(&is_one)).expect("Field must be zero or one to cast to Boolean");
39        is_one
40    }
41}
42
43impl<E: Environment> Cast<Field<E>> for Field<E> {
44    /// Casts a `Field` to a `Field`.
45    #[inline]
46    fn cast(&self) -> Field<E> {
47        self.clone()
48    }
49}
50
51impl<E: Environment> Cast<Group<E>> for Field<E> {
52    /// Casts a `Field` to a `Group`.
53    ///
54    /// This operation attempts to recover the group element from the field element,
55    /// and returns an error if the field element is not a valid x-coordinate.
56    ///
57    /// To cast arbitrary field elements to groups, use `Field::cast_lossy`.
58    #[inline]
59    fn cast(&self) -> Group<E> {
60        Group::from_x_coordinate(self.clone())
61    }
62}
63
64impl<E: Environment, I: IntegerType> Cast<Integer<E, I>> for Field<E> {
65    /// Casts a `Field` to an `Integer`, if the field element is in the integer's range.
66    ///
67    /// To cast arbitrary field elements to integers, use `Field::cast_lossy`.
68    #[inline]
69    fn cast(&self) -> Integer<E, I> {
70        Integer::from_field(self.clone())
71    }
72}
73
74impl<E: Environment> Cast<Scalar<E>> for Field<E> {
75    /// Casts a `Field` to a `Scalar`, if the field element is in the scalar's range.
76    ///
77    /// To cast arbitrary field elements to scalars, use `Field::cast_lossy`.
78    #[inline]
79    fn cast(&self) -> Scalar<E> {
80        Scalar::from_field(self.clone())
81    }
82}
83
84impl<E: Environment> Cast<IdentifierLiteral<E>> for Field<E> {
85    /// Casts a `Field` to an `IdentifierLiteral`.
86    ///
87    /// This operation validates that the field element represents a valid identifier literal.
88    #[inline]
89    fn cast(&self) -> IdentifierLiteral<E> {
90        IdentifierLiteral::from_field(self.clone())
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97    use console::Cast as _;
98    use console_root::{
99        network::MainnetV0,
100        prelude::{One, TestRng, Uniform, Zero},
101    };
102    use snarkvm_circuit_types::environment::{Circuit, Eject, Inject, Mode, UpdatableCount, count_is, count_less_than};
103
104    use std::fmt::Debug;
105
106    const ITERATIONS: usize = 10;
107
108    fn sample_values(
109        i: usize,
110        mode: Mode,
111        rng: &mut TestRng,
112    ) -> (console_root::types::Field<MainnetV0>, Field<Circuit>) {
113        let console_value = match i {
114            0 => console_root::types::Field::<MainnetV0>::zero(),
115            1 => console_root::types::Field::<MainnetV0>::one(),
116            _ => Uniform::rand(rng),
117        };
118        let circuit_value = Field::<Circuit>::new(mode, console_value);
119        (console_value, circuit_value)
120    }
121
122    impl_check_cast!(cast, Field<Circuit>, console_root::types::Field::<MainnetV0>);
123
124    #[test]
125    fn test_field_to_address() {
126        check_cast::<Address<Circuit>, console_root::types::Address<MainnetV0>>(
127            Mode::Constant,
128            count_less_than!(11, 0, 0, 0),
129        );
130        check_cast::<Address<Circuit>, console_root::types::Address<MainnetV0>>(Mode::Public, count_is!(4, 0, 13, 13));
131        check_cast::<Address<Circuit>, console_root::types::Address<MainnetV0>>(Mode::Private, count_is!(4, 0, 13, 13));
132    }
133
134    #[test]
135    fn test_field_to_boolean() {
136        check_cast::<Boolean<Circuit>, console_root::types::Boolean<MainnetV0>>(Mode::Constant, count_is!(2, 0, 0, 0));
137        check_cast::<Boolean<Circuit>, console_root::types::Boolean<MainnetV0>>(Mode::Public, count_is!(0, 0, 5, 6));
138        check_cast::<Boolean<Circuit>, console_root::types::Boolean<MainnetV0>>(Mode::Private, count_is!(0, 0, 5, 6));
139    }
140
141    #[test]
142    fn test_field_to_field() {
143        check_cast::<Field<Circuit>, console_root::types::Field<MainnetV0>>(Mode::Constant, count_is!(0, 0, 0, 0));
144        check_cast::<Field<Circuit>, console_root::types::Field<MainnetV0>>(Mode::Public, count_is!(0, 0, 0, 0));
145        check_cast::<Field<Circuit>, console_root::types::Field<MainnetV0>>(Mode::Private, count_is!(0, 0, 0, 0));
146    }
147
148    #[test]
149    fn test_field_to_group() {
150        check_cast::<Group<Circuit>, console_root::types::Group<MainnetV0>>(
151            Mode::Constant,
152            count_less_than!(11, 0, 0, 0),
153        );
154        check_cast::<Group<Circuit>, console_root::types::Group<MainnetV0>>(Mode::Public, count_is!(4, 0, 13, 13));
155        check_cast::<Group<Circuit>, console_root::types::Group<MainnetV0>>(Mode::Private, count_is!(4, 0, 13, 13));
156    }
157
158    #[test]
159    fn test_field_to_i8() {
160        check_cast::<I8<Circuit>, console_root::types::I8<MainnetV0>>(Mode::Constant, count_is!(8, 0, 0, 0));
161        check_cast::<I8<Circuit>, console_root::types::I8<MainnetV0>>(Mode::Public, count_is!(0, 0, 8, 9));
162        check_cast::<I8<Circuit>, console_root::types::I8<MainnetV0>>(Mode::Private, count_is!(0, 0, 8, 9));
163    }
164
165    #[test]
166    fn test_field_to_i16() {
167        check_cast::<I16<Circuit>, console_root::types::I16<MainnetV0>>(Mode::Constant, count_is!(16, 0, 0, 0));
168        check_cast::<I16<Circuit>, console_root::types::I16<MainnetV0>>(Mode::Public, count_is!(0, 0, 16, 17));
169        check_cast::<I16<Circuit>, console_root::types::I16<MainnetV0>>(Mode::Private, count_is!(0, 0, 16, 17));
170    }
171
172    #[test]
173    fn test_field_to_i32() {
174        check_cast::<I32<Circuit>, console_root::types::I32<MainnetV0>>(Mode::Constant, count_is!(32, 0, 0, 0));
175        check_cast::<I32<Circuit>, console_root::types::I32<MainnetV0>>(Mode::Public, count_is!(0, 0, 32, 33));
176        check_cast::<I32<Circuit>, console_root::types::I32<MainnetV0>>(Mode::Private, count_is!(0, 0, 32, 33));
177    }
178
179    #[test]
180    fn test_field_to_i64() {
181        check_cast::<I64<Circuit>, console_root::types::I64<MainnetV0>>(Mode::Constant, count_is!(64, 0, 0, 0));
182        check_cast::<I64<Circuit>, console_root::types::I64<MainnetV0>>(Mode::Public, count_is!(0, 0, 64, 65));
183        check_cast::<I64<Circuit>, console_root::types::I64<MainnetV0>>(Mode::Private, count_is!(0, 0, 64, 65));
184    }
185
186    #[test]
187    fn test_field_to_i128() {
188        check_cast::<I128<Circuit>, console_root::types::I128<MainnetV0>>(Mode::Constant, count_is!(128, 0, 0, 0));
189        check_cast::<I128<Circuit>, console_root::types::I128<MainnetV0>>(Mode::Public, count_is!(0, 0, 128, 129));
190        check_cast::<I128<Circuit>, console_root::types::I128<MainnetV0>>(Mode::Private, count_is!(0, 0, 128, 129));
191    }
192
193    #[test]
194    fn test_field_to_scalar() {
195        check_cast::<Scalar<Circuit>, console_root::types::Scalar<MainnetV0>>(Mode::Constant, count_is!(253, 0, 0, 0));
196        check_cast::<Scalar<Circuit>, console_root::types::Scalar<MainnetV0>>(Mode::Public, count_is!(0, 0, 755, 759));
197        check_cast::<Scalar<Circuit>, console_root::types::Scalar<MainnetV0>>(Mode::Private, count_is!(0, 0, 755, 759));
198    }
199
200    #[test]
201    fn test_field_to_u8() {
202        check_cast::<U8<Circuit>, console_root::types::U8<MainnetV0>>(Mode::Constant, count_is!(8, 0, 0, 0));
203        check_cast::<U8<Circuit>, console_root::types::U8<MainnetV0>>(Mode::Public, count_is!(0, 0, 8, 9));
204        check_cast::<U8<Circuit>, console_root::types::U8<MainnetV0>>(Mode::Private, count_is!(0, 0, 8, 9));
205    }
206
207    #[test]
208    fn test_field_to_u16() {
209        check_cast::<U16<Circuit>, console_root::types::U16<MainnetV0>>(Mode::Constant, count_is!(16, 0, 0, 0));
210        check_cast::<U16<Circuit>, console_root::types::U16<MainnetV0>>(Mode::Public, count_is!(0, 0, 16, 17));
211        check_cast::<U16<Circuit>, console_root::types::U16<MainnetV0>>(Mode::Private, count_is!(0, 0, 16, 17));
212    }
213
214    #[test]
215    fn test_field_to_u32() {
216        check_cast::<U32<Circuit>, console_root::types::U32<MainnetV0>>(Mode::Constant, count_is!(32, 0, 0, 0));
217        check_cast::<U32<Circuit>, console_root::types::U32<MainnetV0>>(Mode::Public, count_is!(0, 0, 32, 33));
218        check_cast::<U32<Circuit>, console_root::types::U32<MainnetV0>>(Mode::Private, count_is!(0, 0, 32, 33));
219    }
220
221    #[test]
222    fn test_field_to_u64() {
223        check_cast::<U64<Circuit>, console_root::types::U64<MainnetV0>>(Mode::Constant, count_is!(64, 0, 0, 0));
224        check_cast::<U64<Circuit>, console_root::types::U64<MainnetV0>>(Mode::Public, count_is!(0, 0, 64, 65));
225        check_cast::<U64<Circuit>, console_root::types::U64<MainnetV0>>(Mode::Private, count_is!(0, 0, 64, 65));
226    }
227
228    #[test]
229    fn test_field_to_u128() {
230        check_cast::<U128<Circuit>, console_root::types::U128<MainnetV0>>(Mode::Constant, count_is!(128, 0, 0, 0));
231        check_cast::<U128<Circuit>, console_root::types::U128<MainnetV0>>(Mode::Public, count_is!(0, 0, 128, 129));
232        check_cast::<U128<Circuit>, console_root::types::U128<MainnetV0>>(Mode::Private, count_is!(0, 0, 128, 129));
233    }
234}