snarkvm_circuit_program/data/literal/cast/
mod.rs1mod boolean;
17mod field;
18mod integer;
19mod scalar;
20
21use crate::data::{CastLossy, Literal};
22use console::LiteralType;
23use snarkvm_circuit_network::Aleo;
24use snarkvm_circuit_types::prelude::{
25 Address,
26 BitOr,
27 Boolean,
28 Environment,
29 Field,
30 FromBits,
31 FromField,
32 FromGroup,
33 Group,
34 IntegerType,
35 MSB,
36 One,
37 Result,
38 Scalar,
39 ToBits,
40 ToField,
41 ToGroup,
42 Zero,
43 bail,
44 integers::Integer,
45};
46
47#[cfg(test)]
48use snarkvm_circuit_types::prelude::{I8, I16, I32, I64, I128, U8, U16, U32, U64, U128};
49
50pub trait Cast<T: Sized = Self> {
52 fn cast(&self) -> T;
56}
57
58impl<A: Aleo> Literal<A> {
59 pub fn cast(&self, to_type: LiteralType) -> Result<Self> {
71 match self {
72 Self::Address(address) => cast_group_to_type(&address.to_group(), to_type),
73 Self::Boolean(boolean) => cast_boolean_to_type(boolean, to_type),
74 Self::Field(field) => cast_field_to_type(field, to_type),
75 Self::Group(group) => cast_group_to_type(group, to_type),
76 Self::I8(integer) => cast_integer_to_type(integer, to_type),
77 Self::I16(integer) => cast_integer_to_type(integer, to_type),
78 Self::I32(integer) => cast_integer_to_type(integer, to_type),
79 Self::I64(integer) => cast_integer_to_type(integer, to_type),
80 Self::I128(integer) => cast_integer_to_type(integer, to_type),
81 Self::U8(integer) => cast_integer_to_type(integer, to_type),
82 Self::U16(integer) => cast_integer_to_type(integer, to_type),
83 Self::U32(integer) => cast_integer_to_type(integer, to_type),
84 Self::U64(integer) => cast_integer_to_type(integer, to_type),
85 Self::U128(integer) => cast_integer_to_type(integer, to_type),
86 Self::Scalar(scalar) => cast_scalar_to_type(scalar, to_type),
87 Self::Signature(..) => bail!("Cannot cast a signature literal to another type."),
88 Self::String(..) => bail!("Cannot cast a string literal to another type."),
89 }
90 }
91}
92
93macro_rules! impl_cast_body {
95 ($type_name:ident, $cast:ident, $input:expr, $to_type:expr) => {
96 match $to_type {
97 LiteralType::Address => Ok(Literal::Address($input.$cast())),
98 LiteralType::Boolean => Ok(Literal::Boolean($input.$cast())),
99 LiteralType::Field => Ok(Literal::Field($input.$cast())),
100 LiteralType::Group => Ok(Literal::Group($input.$cast())),
101 LiteralType::I8 => Ok(Literal::I8($input.$cast())),
102 LiteralType::I16 => Ok(Literal::I16($input.$cast())),
103 LiteralType::I32 => Ok(Literal::I32($input.$cast())),
104 LiteralType::I64 => Ok(Literal::I64($input.$cast())),
105 LiteralType::I128 => Ok(Literal::I128($input.$cast())),
106 LiteralType::U8 => Ok(Literal::U8($input.$cast())),
107 LiteralType::U16 => Ok(Literal::U16($input.$cast())),
108 LiteralType::U32 => Ok(Literal::U32($input.$cast())),
109 LiteralType::U64 => Ok(Literal::U64($input.$cast())),
110 LiteralType::U128 => Ok(Literal::U128($input.$cast())),
111 LiteralType::Scalar => Ok(Literal::Scalar($input.$cast())),
112 LiteralType::Signature => {
113 bail!(concat!("Cannot cast a ", stringify!($type_name), " literal to a signature type."))
114 }
115 LiteralType::String => {
116 bail!(concat!("Cannot cast a ", stringify!($type_name), " literal to a string type."))
117 }
118 }
119 };
120}
121
122fn cast_boolean_to_type<A: Aleo>(input: &Boolean<A>, to_type: LiteralType) -> Result<Literal<A>> {
124 impl_cast_body!(boolean, cast, input, to_type)
125}
126
127fn cast_field_to_type<A: Aleo>(input: &Field<A>, to_type: LiteralType) -> Result<Literal<A>> {
129 impl_cast_body!(field, cast, input, to_type)
130}
131
132fn cast_group_to_type<A: Aleo>(input: &Group<A>, to_type: LiteralType) -> Result<Literal<A>> {
134 match to_type {
135 LiteralType::Address => Ok(Literal::Address(Address::from_group(input.clone()))),
136 LiteralType::Group => Ok(Literal::Group(input.clone())),
137 _ => cast_field_to_type(&input.to_x_coordinate(), to_type),
138 }
139}
140
141fn cast_integer_to_type<A: Aleo, I: IntegerType>(input: &Integer<A, I>, to_type: LiteralType) -> Result<Literal<A>> {
143 impl_cast_body!(integer, cast, input, to_type)
144}
145
146fn cast_scalar_to_type<A: Aleo>(input: &Scalar<A>, to_type: LiteralType) -> Result<Literal<A>> {
148 impl_cast_body!(scalar, cast, input, to_type)
149}
150
151#[cfg(test)]
152macro_rules! impl_check_cast {
153 ($fun:ident, $circuit_type:ty, $console_type:ty) => {
154 fn check_cast<CircuitType, ConsoleType>(mode: Mode, count: UpdatableCount)
155 where
156 CircuitType: Eject,
157 <CircuitType as Eject>::Primitive: Debug + PartialEq<ConsoleType>,
158 ConsoleType: Debug,
159 $console_type: console::Cast<ConsoleType>,
160 $circuit_type: crate::Cast<CircuitType>,
161 {
162 let rng = &mut TestRng::default();
163 for i in 0..ITERATIONS {
164 let (console_value, circuit_value) = sample_values(i, mode, rng);
165 match console_value.$fun() {
166 Err(_) if mode == Mode::Constant => {
168 assert!(
169 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| circuit_value.$fun())).is_err()
170 )
171 }
172 Err(_) => {
174 Circuit::scope("test", || {
175 if std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| circuit_value.$fun())).is_ok() {
176 assert!(!Circuit::is_satisfied());
177 count.assert_matches(
178 Circuit::num_constants_in_scope(),
179 Circuit::num_public_in_scope(),
180 Circuit::num_private_in_scope(),
181 Circuit::num_constraints_in_scope(),
182 );
183 }
184 });
185 }
186 Ok(expected) => Circuit::scope("test", || {
188 let result = circuit_value.$fun();
189 assert_eq!(result.eject_value(), expected);
190 assert!(Circuit::is_satisfied());
191 count.assert_matches(
192 Circuit::num_constants_in_scope(),
193 Circuit::num_public_in_scope(),
194 Circuit::num_private_in_scope(),
195 Circuit::num_constraints_in_scope(),
196 );
197 }),
198 };
199 Circuit::reset();
200 }
201 }
202 };
203}
204#[cfg(test)]
205pub(super) use impl_check_cast;