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