snarkvm_circuit_program/data/literal/cast_lossy/
scalar.rs

1// Copyright (c) 2019-2025 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> CastLossy<Address<E>> for Scalar<E> {
19    /// Casts a `Scalar` to an `Address`.
20    ///
21    /// This operation converts the scalar into a field element, and then attempts to recover
22    /// the group element to construct the address. See the documentation of `Field::cast_lossy`
23    /// on the `Group` type for more details.
24    #[inline]
25    fn cast_lossy(&self) -> Address<E> {
26        let field: Field<E> = self.cast_lossy();
27        field.cast_lossy()
28    }
29}
30
31impl<E: Environment> CastLossy<Boolean<E>> for Scalar<E> {
32    /// Casts a `Scalar` to a `Boolean`, with lossy truncation.
33    /// This operation returns the least significant bit of the scalar.
34    #[inline]
35    fn cast_lossy(&self) -> Boolean<E> {
36        let bits_le = self.to_bits_le();
37        debug_assert!(!bits_le.is_empty(), "An integer must have at least one bit");
38        bits_le[0].clone()
39    }
40}
41
42impl<E: Environment> CastLossy<Group<E>> for Scalar<E> {
43    /// Casts a `Scalar` to a `Group`.
44    ///
45    /// This operation converts the scalar into a field element, and then attempts to recover
46    /// the group element. See the documentation of `Field::cast_lossy` on the `Group` type
47    /// for more details.
48    #[inline]
49    fn cast_lossy(&self) -> Group<E> {
50        let field: Field<E> = self.cast_lossy();
51        field.cast_lossy()
52    }
53}
54
55impl<E: Environment> CastLossy<Field<E>> for Scalar<E> {
56    /// Casts a `Scalar` to a `Field`.
57    /// This operation is **always** lossless.
58    #[inline]
59    fn cast_lossy(&self) -> Field<E> {
60        self.to_field()
61    }
62}
63
64impl<E: Environment, I: IntegerType> CastLossy<Integer<E, I>> for Scalar<E> {
65    /// Casts a `Scalar` to an `Integer`, with lossy truncation.
66    #[inline]
67    fn cast_lossy(&self) -> Integer<E, I> {
68        debug_assert!(I::BITS < <console::Scalar<E::Network> as console::SizeInBits>::size_in_bits() as u64);
69
70        // Truncate the field to the size of the integer domain.
71        // Slicing here is safe as the base field is larger than the integer domain.
72        Integer::<E, I>::from_bits_le(&self.to_bits_le()[..usize::try_from(I::BITS).unwrap()])
73    }
74}
75
76impl<E: Environment> CastLossy<Scalar<E>> for Scalar<E> {
77    /// Casts a `Scalar` to a `Scalar`.
78    /// This is an identity cast, so it is **always** lossless.
79    #[inline]
80    fn cast_lossy(&self) -> Scalar<E> {
81        self.clone()
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use console::CastLossy as _;
89    use console_root::{
90        network::MainnetV0,
91        prelude::{One, TestRng, Uniform, Zero},
92    };
93    use snarkvm_circuit_types::environment::{Circuit, Eject, Inject, Mode, UpdatableCount, count_is, count_less_than};
94
95    use std::fmt::Debug;
96
97    const ITERATIONS: usize = 100;
98
99    fn sample_values(
100        i: usize,
101        mode: Mode,
102        rng: &mut TestRng,
103    ) -> (console_root::types::Scalar<MainnetV0>, Scalar<Circuit>) {
104        let console_value = match i {
105            0 => console_root::types::Scalar::<MainnetV0>::zero(),
106            1 => console_root::types::Scalar::<MainnetV0>::one(),
107            _ => Uniform::rand(rng),
108        };
109        let circuit_value = Scalar::<Circuit>::new(mode, console_value);
110        (console_value, circuit_value)
111    }
112
113    check_cast_lossy!(cast_lossy, Scalar<Circuit>, console_root::types::Scalar::<MainnetV0>);
114
115    #[test]
116    fn test_scalar_to_address() {
117        check_cast_lossy::<Address<Circuit>, console_root::types::Address<MainnetV0>>(
118            Mode::Constant,
119            count_less_than!(4303, 0, 0, 0),
120        );
121        check_cast_lossy::<Address<Circuit>, console_root::types::Address<MainnetV0>>(
122            Mode::Public,
123            count_is!(2029, 0, 6745, 6750),
124        );
125        check_cast_lossy::<Address<Circuit>, console_root::types::Address<MainnetV0>>(
126            Mode::Private,
127            count_is!(2029, 0, 6745, 6750),
128        );
129    }
130
131    #[test]
132    fn test_scalar_to_boolean() {
133        check_cast_lossy::<Boolean<Circuit>, console_root::types::Boolean<MainnetV0>>(
134            Mode::Constant,
135            count_is!(251, 0, 0, 0),
136        );
137        check_cast_lossy::<Boolean<Circuit>, console_root::types::Boolean<MainnetV0>>(
138            Mode::Public,
139            count_is!(0, 0, 501, 503),
140        );
141        check_cast_lossy::<Boolean<Circuit>, console_root::types::Boolean<MainnetV0>>(
142            Mode::Private,
143            count_is!(0, 0, 501, 503),
144        );
145    }
146
147    #[test]
148    fn test_scalar_to_field() {
149        check_cast_lossy::<Field<Circuit>, console_root::types::Field<MainnetV0>>(
150            Mode::Constant,
151            count_is!(0, 0, 0, 0),
152        );
153        check_cast_lossy::<Field<Circuit>, console_root::types::Field<MainnetV0>>(Mode::Public, count_is!(0, 0, 0, 0));
154        check_cast_lossy::<Field<Circuit>, console_root::types::Field<MainnetV0>>(Mode::Private, count_is!(0, 0, 0, 0));
155    }
156
157    #[test]
158    fn test_scalar_to_group() {
159        check_cast_lossy::<Group<Circuit>, console_root::types::Group<MainnetV0>>(
160            Mode::Constant,
161            count_less_than!(4303, 0, 0, 0),
162        );
163        check_cast_lossy::<Group<Circuit>, console_root::types::Group<MainnetV0>>(
164            Mode::Public,
165            count_is!(2029, 0, 6745, 6750),
166        );
167        check_cast_lossy::<Group<Circuit>, console_root::types::Group<MainnetV0>>(
168            Mode::Private,
169            count_is!(2029, 0, 6745, 6750),
170        );
171    }
172
173    #[test]
174    fn test_scalar_to_i8() {
175        check_cast_lossy::<I8<Circuit>, console_root::types::I8<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
176        check_cast_lossy::<I8<Circuit>, console_root::types::I8<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
177        check_cast_lossy::<I8<Circuit>, console_root::types::I8<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
178    }
179
180    #[test]
181    fn test_scalar_to_i16() {
182        check_cast_lossy::<I16<Circuit>, console_root::types::I16<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
183        check_cast_lossy::<I16<Circuit>, console_root::types::I16<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
184        check_cast_lossy::<I16<Circuit>, console_root::types::I16<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
185    }
186
187    #[test]
188    fn test_scalar_to_i32() {
189        check_cast_lossy::<I32<Circuit>, console_root::types::I32<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
190        check_cast_lossy::<I32<Circuit>, console_root::types::I32<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
191        check_cast_lossy::<I32<Circuit>, console_root::types::I32<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
192    }
193
194    #[test]
195    fn test_scalar_to_i64() {
196        check_cast_lossy::<I64<Circuit>, console_root::types::I64<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
197        check_cast_lossy::<I64<Circuit>, console_root::types::I64<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
198        check_cast_lossy::<I64<Circuit>, console_root::types::I64<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
199    }
200
201    #[test]
202    fn test_scalar_to_i128() {
203        check_cast_lossy::<I128<Circuit>, console_root::types::I128<MainnetV0>>(
204            Mode::Constant,
205            count_is!(251, 0, 0, 0),
206        );
207        check_cast_lossy::<I128<Circuit>, console_root::types::I128<MainnetV0>>(
208            Mode::Public,
209            count_is!(0, 0, 501, 503),
210        );
211        check_cast_lossy::<I128<Circuit>, console_root::types::I128<MainnetV0>>(
212            Mode::Private,
213            count_is!(0, 0, 501, 503),
214        );
215    }
216
217    #[test]
218    fn test_scalar_to_scalar() {
219        check_cast_lossy::<Scalar<Circuit>, console_root::types::Scalar<MainnetV0>>(
220            Mode::Constant,
221            count_is!(0, 0, 0, 0),
222        );
223        check_cast_lossy::<Scalar<Circuit>, console_root::types::Scalar<MainnetV0>>(
224            Mode::Public,
225            count_is!(0, 0, 0, 0),
226        );
227        check_cast_lossy::<Scalar<Circuit>, console_root::types::Scalar<MainnetV0>>(
228            Mode::Private,
229            count_is!(0, 0, 0, 0),
230        );
231    }
232
233    #[test]
234    fn test_scalar_to_u8() {
235        check_cast_lossy::<U8<Circuit>, console_root::types::U8<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
236        check_cast_lossy::<U8<Circuit>, console_root::types::U8<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
237        check_cast_lossy::<U8<Circuit>, console_root::types::U8<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
238    }
239
240    #[test]
241    fn test_scalar_to_u16() {
242        check_cast_lossy::<U16<Circuit>, console_root::types::U16<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
243        check_cast_lossy::<U16<Circuit>, console_root::types::U16<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
244        check_cast_lossy::<U16<Circuit>, console_root::types::U16<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
245    }
246
247    #[test]
248    fn test_scalar_to_u32() {
249        check_cast_lossy::<U32<Circuit>, console_root::types::U32<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
250        check_cast_lossy::<U32<Circuit>, console_root::types::U32<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
251        check_cast_lossy::<U32<Circuit>, console_root::types::U32<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
252    }
253
254    #[test]
255    fn test_scalar_to_u64() {
256        check_cast_lossy::<U64<Circuit>, console_root::types::U64<MainnetV0>>(Mode::Constant, count_is!(251, 0, 0, 0));
257        check_cast_lossy::<U64<Circuit>, console_root::types::U64<MainnetV0>>(Mode::Public, count_is!(0, 0, 501, 503));
258        check_cast_lossy::<U64<Circuit>, console_root::types::U64<MainnetV0>>(Mode::Private, count_is!(0, 0, 501, 503));
259    }
260
261    #[test]
262    fn test_scalar_to_u128() {
263        check_cast_lossy::<U128<Circuit>, console_root::types::U128<MainnetV0>>(
264            Mode::Constant,
265            count_is!(251, 0, 0, 0),
266        );
267        check_cast_lossy::<U128<Circuit>, console_root::types::U128<MainnetV0>>(
268            Mode::Public,
269            count_is!(0, 0, 501, 503),
270        );
271        check_cast_lossy::<U128<Circuit>, console_root::types::U128<MainnetV0>>(
272            Mode::Private,
273            count_is!(0, 0, 501, 503),
274        );
275    }
276}