Skip to main content

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