leo_ast/interpreter_value/
evaluate.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use snarkvm::prelude::{Double, Inverse as _, Pow as _, ProgramID, Square as _, SquareRoot as _};
18
19use leo_errors::{InterpreterHalt, Result};
20use leo_span::Span;
21
22use crate::{
23    BinaryOperation,
24    FromStrRadix as _,
25    IntegerType,
26    Literal,
27    LiteralVariant,
28    Type,
29    UnaryOperation,
30    fail2,
31    halt_no_span2,
32    halt2,
33    tc_fail2,
34};
35
36use super::*;
37
38impl Value {
39    /// Are the values equal, according to SnarkVM?
40    ///
41    /// We use this rather than the Eq trait so we can
42    /// fail when comparing values of different types,
43    /// rather than just returning false.
44    pub fn eq(&self, rhs: &Self) -> Result<bool> {
45        if self.id != rhs.id {
46            return Ok(false);
47        }
48        use ValueVariants::*;
49        Ok(match (&self.contents, &rhs.contents) {
50            (Unsuffixed(..), _) | (_, Unsuffixed(..)) => halt_no_span2!("Error"),
51            (Unit, Unit) => true,
52            (Tuple(x), Tuple(y)) => {
53                if x.len() != y.len() {
54                    return Ok(false);
55                }
56                for (x0, y0) in x.iter().zip(y) {
57                    if !x0.eq(y0)? {
58                        return Ok(false);
59                    }
60                }
61                true
62            }
63            (Svm(x), Svm(y)) => x == y,
64            (_, _) => halt_no_span2!("Type failure"),
65        })
66    }
67
68    /// Resolves an unsuffixed literal to a typed `Value` using the provided optional `Type`. If the value is unsuffixed
69    /// and a type is provided, parses the string into the corresponding `Value` variant. Handles integers of various
70    /// widths and special types like `Field`, `Group`, and `Scalar`. If no type is given or the value is already typed,
71    /// returns the original value. Returns an error if type inference is not possible or parsing fails.
72    pub fn resolve_if_unsuffixed(&self, ty: &Option<Type>, span: Span) -> Result<Value> {
73        if let ValueVariants::Unsuffixed(s) = &self.contents {
74            if let Some(ty) = ty {
75                let value = match ty {
76                    Type::Integer(IntegerType::U8) => {
77                        let s = s.replace("_", "");
78                        u8::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
79                    }
80                    Type::Integer(IntegerType::U16) => {
81                        let s = s.replace("_", "");
82                        u16::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
83                    }
84                    Type::Integer(IntegerType::U32) => {
85                        let s = s.replace("_", "");
86                        u32::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
87                    }
88                    Type::Integer(IntegerType::U64) => {
89                        let s = s.replace("_", "");
90                        u64::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
91                    }
92                    Type::Integer(IntegerType::U128) => {
93                        let s = s.replace("_", "");
94                        u128::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
95                    }
96                    Type::Integer(IntegerType::I8) => {
97                        let s = s.replace("_", "");
98                        i8::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
99                    }
100                    Type::Integer(IntegerType::I16) => {
101                        let s = s.replace("_", "");
102                        i16::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
103                    }
104                    Type::Integer(IntegerType::I32) => {
105                        let s = s.replace("_", "");
106                        i32::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
107                    }
108                    Type::Integer(IntegerType::I64) => {
109                        let s = s.replace("_", "");
110                        i64::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
111                    }
112                    Type::Integer(IntegerType::I128) => {
113                        let s = s.replace("_", "");
114                        i128::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
115                    }
116                    Type::Field => {
117                        SvmLiteralParam::Field(prepare_snarkvm_string(s, "field").parse().expect_tc(span)?).into()
118                    }
119                    Type::Group => {
120                        SvmLiteralParam::Group(prepare_snarkvm_string(s, "group").parse().expect_tc(span)?).into()
121                    }
122                    Type::Scalar => {
123                        SvmLiteralParam::Scalar(prepare_snarkvm_string(s, "scalar").parse().expect_tc(span)?).into()
124                    }
125                    _ => {
126                        halt2!(span, "cannot infer type of unsuffixed literal")
127                    }
128                };
129                Ok(value)
130            } else {
131                Ok(self.clone())
132            }
133        } else {
134            Ok(self.clone())
135        }
136    }
137}
138
139pub fn literal_to_value(literal: &Literal, expected_ty: &Option<Type>) -> Result<Value> {
140    Ok(match &literal.variant {
141        LiteralVariant::Boolean(b) => (*b).into(),
142        LiteralVariant::Integer(IntegerType::U8, s, ..) => {
143            let s = s.replace("_", "");
144            u8::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
145        }
146        LiteralVariant::Integer(IntegerType::U16, s, ..) => {
147            let s = s.replace("_", "");
148            u16::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
149        }
150        LiteralVariant::Integer(IntegerType::U32, s, ..) => {
151            let s = s.replace("_", "");
152            u32::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
153        }
154        LiteralVariant::Integer(IntegerType::U64, s, ..) => {
155            let s = s.replace("_", "");
156            u64::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
157        }
158        LiteralVariant::Integer(IntegerType::U128, s, ..) => {
159            let s = s.replace("_", "");
160            u128::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
161        }
162        LiteralVariant::Integer(IntegerType::I8, s, ..) => {
163            let s = s.replace("_", "");
164            i8::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
165        }
166        LiteralVariant::Integer(IntegerType::I16, s, ..) => {
167            let s = s.replace("_", "");
168            i16::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
169        }
170        LiteralVariant::Integer(IntegerType::I32, s, ..) => {
171            let s = s.replace("_", "");
172            i32::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
173        }
174        LiteralVariant::Integer(IntegerType::I64, s, ..) => {
175            let s = s.replace("_", "");
176            i64::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
177        }
178        LiteralVariant::Integer(IntegerType::I128, s, ..) => {
179            let s = s.replace("_", "");
180            i128::from_str_by_radix(&s).expect("Parsing guarantees this works.").into()
181        }
182        LiteralVariant::Field(s) => {
183            SvmLiteralParam::Field(prepare_snarkvm_string(s, "field").parse().expect_tc(literal.span)?).into()
184        }
185        LiteralVariant::Group(s) => {
186            SvmLiteralParam::Group(prepare_snarkvm_string(s, "group").parse().expect_tc(literal.span)?).into()
187        }
188
189        LiteralVariant::Address(s) => {
190            if s.ends_with(".aleo") {
191                let program_id: ProgramID<CurrentNetwork> = s.parse()?;
192                program_id.to_address()?.into()
193            } else {
194                let address: Address = s.parse().expect_tc(literal.span)?;
195                address.into()
196            }
197        }
198        LiteralVariant::Scalar(s) => {
199            SvmLiteralParam::Scalar(prepare_snarkvm_string(s, "scalar").parse().expect_tc(literal.span)?).into()
200        }
201        LiteralVariant::Unsuffixed(s) => {
202            let unsuffixed = Value { id: None, contents: ValueVariants::Unsuffixed(s.clone()) };
203            unsuffixed.resolve_if_unsuffixed(expected_ty, literal.span)?
204        }
205        LiteralVariant::None => halt_no_span2!(""),
206        LiteralVariant::String(..) => tc_fail2!(),
207    })
208}
209
210/// Resolves an unsuffixed operand for a unary operation by inferring its type based on the operation and an optional
211/// expected type. Uses predefined types (`Field` or `Group`) for specific operations, otherwise defaults to the expected
212/// type if available. Returns the resolved `Value` or an error if type resolution fails.
213fn resolve_unsuffixed_unary_op_operand(
214    val: &Value,
215    op: &UnaryOperation,
216    expected_ty: &Option<Type>,
217    span: &Span,
218) -> Result<Value> {
219    match op {
220        UnaryOperation::Inverse | UnaryOperation::Square | UnaryOperation::SquareRoot => {
221            // These ops only take a `field` and return a `field`
222            val.resolve_if_unsuffixed(&Some(Type::Field), *span)
223        }
224        UnaryOperation::ToXCoordinate | UnaryOperation::ToYCoordinate => {
225            // These ops only take a `Group`
226            val.resolve_if_unsuffixed(&Some(Type::Group), *span)
227        }
228        _ => {
229            // All other unary ops take the same type as the their return type
230            val.resolve_if_unsuffixed(expected_ty, *span)
231        }
232    }
233}
234
235/// Evaluate a unary operation.
236pub fn evaluate_unary(span: Span, op: UnaryOperation, value: &Value, expected_ty: &Option<Type>) -> Result<Value> {
237    let value = resolve_unsuffixed_unary_op_operand(value, &op, expected_ty, &span)?;
238    let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(literal, ..))) = &value.contents else {
239        halt2!(span, "Type error");
240    };
241    let value_result: Value = match op {
242        UnaryOperation::Abs => match literal {
243            SvmLiteralParam::I8(x) => {
244                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overflow"))?.into()
245            }
246            SvmLiteralParam::I16(x) => {
247                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
248            }
249            SvmLiteralParam::I32(x) => {
250                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
251            }
252            SvmLiteralParam::I64(x) => {
253                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
254            }
255            SvmLiteralParam::I128(x) => {
256                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
257            }
258            _ => halt2!(span, "Type error"),
259        },
260        UnaryOperation::AbsWrapped => match literal {
261            SvmLiteralParam::I8(x) => (x.unsigned_abs() as i8).into(),
262            SvmLiteralParam::I16(x) => (x.unsigned_abs() as i16).into(),
263            SvmLiteralParam::I32(x) => (x.unsigned_abs() as i32).into(),
264            SvmLiteralParam::I64(x) => (x.unsigned_abs() as i64).into(),
265            SvmLiteralParam::I128(x) => (x.unsigned_abs() as i128).into(),
266            _ => halt2!(span, "Type error"),
267        },
268        UnaryOperation::Double => match literal {
269            SvmLiteralParam::Field(x) => <Field as Double>::double(x).into(),
270            SvmLiteralParam::Group(x) => <Group as Double>::double(x).into(),
271            _ => halt2!(span, "Type error"),
272        },
273        UnaryOperation::Inverse => match literal {
274            SvmLiteralParam::Field(x) => {
275                let Ok(y) = x.inverse() else {
276                    halt2!(span, "attempt to invert 0field");
277                };
278                y.into()
279            }
280            _ => halt2!(span, "Can only invert fields"),
281        },
282        UnaryOperation::Negate => match literal {
283            SvmLiteralParam::I8(x) => {
284                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
285            }
286            SvmLiteralParam::I16(x) => {
287                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
288            }
289            SvmLiteralParam::I32(x) => {
290                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
291            }
292            SvmLiteralParam::I64(x) => {
293                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
294            }
295            SvmLiteralParam::I128(x) => {
296                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
297            }
298            SvmLiteralParam::Group(x) => (-*x).into(),
299            SvmLiteralParam::Field(x) => (-*x).into(),
300            _ => halt2!(span, "Type error"),
301        },
302        UnaryOperation::Not => match literal {
303            SvmLiteralParam::Boolean(x) => (!**x).into(),
304            SvmLiteralParam::U8(x) => (!**x).into(),
305            SvmLiteralParam::U16(x) => (!**x).into(),
306            SvmLiteralParam::U32(x) => (!**x).into(),
307            SvmLiteralParam::U64(x) => (!**x).into(),
308            SvmLiteralParam::U128(x) => (!**x).into(),
309            SvmLiteralParam::I8(x) => (!**x).into(),
310            SvmLiteralParam::I16(x) => (!**x).into(),
311            SvmLiteralParam::I32(x) => (!**x).into(),
312            SvmLiteralParam::I64(x) => (!**x).into(),
313            SvmLiteralParam::I128(x) => (!**x).into(),
314            _ => halt2!(span, "Type error"),
315        },
316        UnaryOperation::Square => match literal {
317            SvmLiteralParam::Field(x) => x.square().into(),
318            _ => halt2!(span, "Can only square fields"),
319        },
320        UnaryOperation::SquareRoot => match literal {
321            SvmLiteralParam::Field(x) => {
322                x.square_root().map_err::<InterpreterHalt, _>(|e| fail2!(span, "square root failure: {e}"))?.into()
323            }
324            _ => halt2!(span, "Can only apply square_root to fields"),
325        },
326        UnaryOperation::ToXCoordinate => match literal {
327            SvmLiteral::Group(x) => x.to_x_coordinate().into(),
328            _ => tc_fail2!(),
329        },
330        UnaryOperation::ToYCoordinate => match literal {
331            SvmLiteral::Group(x) => x.to_y_coordinate().into(),
332            _ => tc_fail2!(),
333        },
334    };
335
336    Ok(value_result)
337}
338
339/// Resolves unsuffixed numeric operands for binary operations by inferring types based on the other operand, the
340/// operation type, and an optional expected type. Handles special cases for multiplication and exponentiation with
341/// additional logic for `Group`, `Scalar`, and `Field` type inference. Ensures that both operands are resolved to
342/// compatible types before evaluation. Returns a tuple of resolved `Value`s or an error if resolution fails.
343fn resolve_unsuffixed_binary_op_operands(
344    lhs: &Value,
345    rhs: &Value,
346    op: &BinaryOperation,
347    expected_ty: &Option<Type>,
348    span: &Span,
349) -> Result<(Value, Value)> {
350    use Type::*;
351
352    let lhs_ty = lhs.get_numeric_type();
353    let rhs_ty = rhs.get_numeric_type();
354
355    Ok(match op {
356        BinaryOperation::Mul => {
357            // For a `Mul`, if on operand is a Scalar, then the other must ba a `Group`. Otherwise, both ops must have
358            // the same type as the return type of the multiplication.
359            let lhs = match rhs_ty {
360                Some(Group) => lhs.resolve_if_unsuffixed(&Some(Scalar), *span)?,
361                Some(Scalar) => lhs.resolve_if_unsuffixed(&Some(Group), *span)?,
362                _ => lhs.resolve_if_unsuffixed(&rhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
363            };
364
365            let rhs = match lhs_ty {
366                Some(Group) => rhs.resolve_if_unsuffixed(&Some(Scalar), *span)?,
367                Some(Scalar) => rhs.resolve_if_unsuffixed(&Some(Group), *span)?,
368                _ => rhs.resolve_if_unsuffixed(&lhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
369            };
370
371            (lhs, rhs)
372        }
373        BinaryOperation::Pow => {
374            // For a `Pow`, if one operand is a `Field`, then the other must also be a `Field.
375            // Otherwise, only the `lhs` must match the return type.
376            let lhs_resolved = lhs
377                .resolve_if_unsuffixed(&rhs_ty.filter(|ty| matches!(ty, Type::Field)), *span)?
378                .resolve_if_unsuffixed(expected_ty, *span)?;
379
380            let rhs_resolved = rhs.resolve_if_unsuffixed(&lhs_ty.filter(|ty| matches!(ty, Type::Field)), *span)?;
381
382            (lhs_resolved, rhs_resolved)
383        }
384        _ => (
385            lhs.resolve_if_unsuffixed(&rhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
386            rhs.resolve_if_unsuffixed(&lhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
387        ),
388    })
389}
390
391/// Evaluate a binary operation.
392pub fn evaluate_binary(
393    span: Span,
394    op: BinaryOperation,
395    lhs: &Value,
396    rhs: &Value,
397    expected_ty: &Option<Type>,
398) -> Result<Value> {
399    let (lhs, rhs) = resolve_unsuffixed_binary_op_operands(lhs, rhs, &op, expected_ty, &span)?;
400
401    match op {
402        BinaryOperation::Eq => return lhs.eq(&rhs).map(|x| x.into()),
403        BinaryOperation::Neq => return lhs.eq(&rhs).map(|x| (!x).into()),
404        _ => {}
405    }
406
407    let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(lhs, ..))) = &lhs.contents else {
408        halt2!(span, "Type error");
409    };
410    let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(rhs, ..))) = &rhs.contents else {
411        halt2!(span, "Type error");
412    };
413    let value = match op {
414        BinaryOperation::Add => {
415            let Some(value): Option<Value> = (match (lhs, rhs) {
416                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x).checked_add(**y).map(|z| z.into()),
417                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x).checked_add(**y).map(|z| z.into()),
418                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x).checked_add(**y).map(|z| z.into()),
419                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x).checked_add(**y).map(|z| z.into()),
420                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x).checked_add(**y).map(|z| z.into()),
421                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x).checked_add(**y).map(|z| z.into()),
422                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x).checked_add(**y).map(|z| z.into()),
423                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x).checked_add(**y).map(|z| z.into()),
424                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x).checked_add(**y).map(|z| z.into()),
425                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x).checked_add(**y).map(|z| z.into()),
426                (SvmLiteralParam::Group(x), SvmLiteralParam::Group(y)) => Some((*x + y).into()),
427                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => Some((*x + y).into()),
428                (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => Some((*x + y).into()),
429                _ => halt2!(span, "Type error"),
430            }) else {
431                halt2!(span, "add overflow");
432            };
433            value
434        }
435        BinaryOperation::AddWrapped => match (lhs, rhs) {
436            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x).wrapping_add(**y).into(),
437            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x).wrapping_add(**y).into(),
438            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x).wrapping_add(**y).into(),
439            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x).wrapping_add(**y).into(),
440            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x).wrapping_add(**y).into(),
441            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x).wrapping_add(**y).into(),
442            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x).wrapping_add(**y).into(),
443            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x).wrapping_add(**y).into(),
444            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x).wrapping_add(**y).into(),
445            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x).wrapping_add(**y).into(),
446            _ => halt2!(span, "Type error"),
447        },
448        BinaryOperation::And => match (lhs, rhs) {
449            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x && **y).into(),
450            _ => halt2!(span, "Type error"),
451        },
452        BinaryOperation::BitwiseAnd => match (lhs, rhs) {
453            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x & **y).into(),
454            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x & **y).into(),
455            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x & **y).into(),
456            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x & **y).into(),
457            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x & **y).into(),
458            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x & **y).into(),
459            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x & **y).into(),
460            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x & **y).into(),
461            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x & **y).into(),
462            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x & **y).into(),
463            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x & **y).into(),
464            _ => halt2!(span, "Type error"),
465        },
466        BinaryOperation::Div => {
467            let Some(value) = (match (lhs, rhs) {
468                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x).checked_div(**y).map(|z| z.into()),
469                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x).checked_div(**y).map(|z| z.into()),
470                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x).checked_div(**y).map(|z| z.into()),
471                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x).checked_div(**y).map(|z| z.into()),
472                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x).checked_div(**y).map(|z| z.into()),
473                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x).checked_div(**y).map(|z| z.into()),
474                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x).checked_div(**y).map(|z| z.into()),
475                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x).checked_div(**y).map(|z| z.into()),
476                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x).checked_div(**y).map(|z| z.into()),
477                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x).checked_div(**y).map(|z| z.into()),
478                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => y.inverse().map(|y| (*x * y).into()).ok(),
479                _ => halt2!(span, "Type error"),
480            }) else {
481                halt2!(span, "div overflow");
482            };
483            value
484        }
485        BinaryOperation::DivWrapped => match (lhs, rhs) {
486            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
487            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
488            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
489            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
490            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
491            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
492            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
493            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
494            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
495            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
496            _ => halt2!(span, "Type error"),
497        },
498        BinaryOperation::Eq => unreachable!("This case was handled above"),
499        BinaryOperation::Gte => match (lhs, rhs) {
500            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x >= *y).into(),
501            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x >= *y).into(),
502            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x >= *y).into(),
503            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x >= *y).into(),
504            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x >= *y).into(),
505            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x >= *y).into(),
506            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x >= *y).into(),
507            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x >= *y).into(),
508            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x >= *y).into(),
509            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x >= *y).into(),
510            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x >= *y).into(),
511            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x >= *y).into(),
512            _ => halt2!(span, "Type error"),
513        },
514        BinaryOperation::Gt => match (lhs, rhs) {
515            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x > *y).into(),
516            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x > *y).into(),
517            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x > *y).into(),
518            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x > *y).into(),
519            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x > *y).into(),
520            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x > *y).into(),
521            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x > *y).into(),
522            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x > *y).into(),
523            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x > *y).into(),
524            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x > *y).into(),
525            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x > *y).into(),
526            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x > *y).into(),
527            _ => halt2!(span, "Type error"),
528        },
529        BinaryOperation::Lte => match (lhs, rhs) {
530            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x <= *y).into(),
531            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x <= *y).into(),
532            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x <= *y).into(),
533            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x <= *y).into(),
534            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x <= *y).into(),
535            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x <= *y).into(),
536            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x <= *y).into(),
537            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x <= *y).into(),
538            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x <= *y).into(),
539            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x <= *y).into(),
540            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x <= *y).into(),
541            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x <= *y).into(),
542            _ => halt2!(span, "Type error"),
543        },
544        BinaryOperation::Lt => match (lhs, rhs) {
545            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x < *y).into(),
546            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x < *y).into(),
547            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x < *y).into(),
548            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x < *y).into(),
549            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x < *y).into(),
550            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x < *y).into(),
551            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x < *y).into(),
552            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x < *y).into(),
553            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x < *y).into(),
554            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x < *y).into(),
555            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x < *y).into(),
556            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x < *y).into(),
557            _ => halt2!(span, "Type error"),
558        },
559        BinaryOperation::Mod => {
560            let Some(value) = (match (lhs, rhs) {
561                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => x.checked_rem(**y).map(|z| z.into()),
562                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => x.checked_rem(**y).map(|z| z.into()),
563                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => x.checked_rem(**y).map(|z| z.into()),
564                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => x.checked_rem(**y).map(|z| z.into()),
565                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => x.checked_rem(**y).map(|z| z.into()),
566                _ => halt2!(span, "Type error"),
567            }) else {
568                halt2!(span, "mod overflow");
569            };
570            value
571        }
572        BinaryOperation::Mul => {
573            let Some(value) = (match (lhs, rhs) {
574                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => x.checked_mul(**y).map(|z| z.into()),
575                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => x.checked_mul(**y).map(|z| z.into()),
576                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => x.checked_mul(**y).map(|z| z.into()),
577                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => x.checked_mul(**y).map(|z| z.into()),
578                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => x.checked_mul(**y).map(|z| z.into()),
579                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => x.checked_mul(**y).map(|z| z.into()),
580                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => x.checked_mul(**y).map(|z| z.into()),
581                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => x.checked_mul(**y).map(|z| z.into()),
582                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => x.checked_mul(**y).map(|z| z.into()),
583                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => x.checked_mul(**y).map(|z| z.into()),
584                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => Some((*x * y).into()),
585                (SvmLiteralParam::Group(x), SvmLiteralParam::Scalar(y)) => Some((*x * y).into()),
586                (SvmLiteralParam::Scalar(x), SvmLiteralParam::Group(y)) => Some((*x * y).into()),
587                _ => halt2!(span, "Type error"),
588            }) else {
589                halt2!(span, "mul overflow");
590            };
591            value
592        }
593        BinaryOperation::MulWrapped => match (lhs, rhs) {
594            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => x.wrapping_mul(**y).into(),
595            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => x.wrapping_mul(**y).into(),
596            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => x.wrapping_mul(**y).into(),
597            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => x.wrapping_mul(**y).into(),
598            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => x.wrapping_mul(**y).into(),
599            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => x.wrapping_mul(**y).into(),
600            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => x.wrapping_mul(**y).into(),
601            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => x.wrapping_mul(**y).into(),
602            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => x.wrapping_mul(**y).into(),
603            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => x.wrapping_mul(**y).into(),
604            _ => halt2!(span, "Type error"),
605        },
606
607        BinaryOperation::Nand => match (lhs, rhs) {
608            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (!(**x & **y)).into(),
609            _ => halt2!(span, "Type error"),
610        },
611
612        BinaryOperation::Neq => unreachable!("This case was handled above"),
613
614        BinaryOperation::Nor => match (lhs, rhs) {
615            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (!(**x | **y)).into(),
616            _ => halt2!(span, "Type error"),
617        },
618
619        BinaryOperation::Or => match (lhs, rhs) {
620            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x | **y).into(),
621            _ => halt2!(span, "Type error"),
622        },
623
624        BinaryOperation::BitwiseOr => match (lhs, rhs) {
625            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x | **y).into(),
626            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x | **y).into(),
627            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x | **y).into(),
628            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x | **y).into(),
629            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x | **y).into(),
630            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x | **y).into(),
631            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x | **y).into(),
632            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x | **y).into(),
633            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x | **y).into(),
634            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x | **y).into(),
635            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x | **y).into(),
636            _ => halt2!(span, "Type error"),
637        },
638
639        BinaryOperation::Pow => {
640            if let (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) = (&lhs, &rhs) {
641                x.pow(y).into()
642            } else {
643                let rhs: u32 = match rhs {
644                    SvmLiteralParam::U8(y) => (**y).into(),
645                    SvmLiteralParam::U16(y) => (**y).into(),
646                    SvmLiteralParam::U32(y) => **y,
647                    _ => tc_fail2!(),
648                };
649
650                let Some(value) = (match lhs {
651                    SvmLiteralParam::U8(x) => x.checked_pow(rhs).map(|z| z.into()),
652                    SvmLiteralParam::U16(x) => x.checked_pow(rhs).map(|z| z.into()),
653                    SvmLiteralParam::U32(x) => x.checked_pow(rhs).map(|z| z.into()),
654                    SvmLiteralParam::U64(x) => x.checked_pow(rhs).map(|z| z.into()),
655                    SvmLiteralParam::U128(x) => x.checked_pow(rhs).map(|z| z.into()),
656                    SvmLiteralParam::I8(x) => x.checked_pow(rhs).map(|z| z.into()),
657                    SvmLiteralParam::I16(x) => x.checked_pow(rhs).map(|z| z.into()),
658                    SvmLiteralParam::I32(x) => x.checked_pow(rhs).map(|z| z.into()),
659                    SvmLiteralParam::I64(x) => x.checked_pow(rhs).map(|z| z.into()),
660                    SvmLiteralParam::I128(x) => x.checked_pow(rhs).map(|z| z.into()),
661                    _ => halt2!(span, "Type error"),
662                }) else {
663                    halt2!(span, "pow overflow");
664                };
665                value
666            }
667        }
668        BinaryOperation::PowWrapped => {
669            let rhs: u32 = match rhs {
670                SvmLiteralParam::U8(y) => (**y).into(),
671                SvmLiteralParam::U16(y) => (**y).into(),
672                SvmLiteralParam::U32(y) => **y,
673                _ => halt2!(span, "Type error"),
674            };
675
676            match lhs {
677                SvmLiteralParam::U8(x) => x.wrapping_pow(rhs).into(),
678                SvmLiteralParam::U16(x) => x.wrapping_pow(rhs).into(),
679                SvmLiteralParam::U32(x) => x.wrapping_pow(rhs).into(),
680                SvmLiteralParam::U64(x) => x.wrapping_pow(rhs).into(),
681                SvmLiteralParam::U128(x) => x.wrapping_pow(rhs).into(),
682                SvmLiteralParam::I8(x) => x.wrapping_pow(rhs).into(),
683                SvmLiteralParam::I16(x) => x.wrapping_pow(rhs).into(),
684                SvmLiteralParam::I32(x) => x.wrapping_pow(rhs).into(),
685                SvmLiteralParam::I64(x) => x.wrapping_pow(rhs).into(),
686                SvmLiteralParam::I128(x) => x.wrapping_pow(rhs).into(),
687                _ => halt2!(span, "Type error"),
688            }
689        }
690
691        BinaryOperation::Rem => {
692            let Some(value) = (match (lhs, rhs) {
693                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x).checked_rem(**y).map(|z| z.into()),
694                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x).checked_rem(**y).map(|z| z.into()),
695                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x).checked_rem(**y).map(|z| z.into()),
696                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x).checked_rem(**y).map(|z| z.into()),
697                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x).checked_rem(**y).map(|z| z.into()),
698                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x).checked_rem(**y).map(|z| z.into()),
699                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x).checked_rem(**y).map(|z| z.into()),
700                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x).checked_rem(**y).map(|z| z.into()),
701                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x).checked_rem(**y).map(|z| z.into()),
702                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x).checked_rem(**y).map(|z| z.into()),
703                _ => halt2!(span, "Type error"),
704            }) else {
705                halt2!(span, "rem error");
706            };
707            value
708        }
709
710        BinaryOperation::RemWrapped => match (lhs, rhs) {
711            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
712            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
713            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
714            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
715            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
716            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
717            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
718            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
719            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
720            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
721            _ => halt2!(span, "Type error"),
722        },
723
724        BinaryOperation::Shl => {
725            let rhs: u32 = match rhs {
726                SvmLiteralParam::U8(y) => (**y).into(),
727                SvmLiteralParam::U16(y) => (**y).into(),
728                SvmLiteralParam::U32(y) => **y,
729                _ => halt2!(span, "Type error"),
730            };
731            match lhs {
732                SvmLiteralParam::U8(_) | SvmLiteralParam::I8(_) if rhs >= 8 => halt2!(span, "shl overflow"),
733                SvmLiteralParam::U16(_) | SvmLiteralParam::I16(_) if rhs >= 16 => halt2!(span, "shl overflow"),
734                SvmLiteralParam::U32(_) | SvmLiteralParam::I32(_) if rhs >= 32 => halt2!(span, "shl overflow"),
735                SvmLiteralParam::U64(_) | SvmLiteralParam::I64(_) if rhs >= 64 => halt2!(span, "shl overflow"),
736                SvmLiteralParam::U128(_) | SvmLiteralParam::I128(_) if rhs >= 128 => halt2!(span, "shl overflow"),
737                SvmLiteralParam::U8(x) => {
738                    let before_ones = x.count_ones();
739                    let shifted = (**x) << rhs;
740                    let after_ones = x.count_ones();
741                    if before_ones != after_ones {
742                        halt2!(span, "shl");
743                    }
744                    shifted.into()
745                }
746                SvmLiteralParam::U16(x) => {
747                    let before_ones = x.count_ones();
748                    let shifted = (**x) << rhs;
749                    let after_ones = x.count_ones();
750                    if before_ones != after_ones {
751                        halt2!(span, "shl");
752                    }
753                    shifted.into()
754                }
755                SvmLiteralParam::U32(x) => {
756                    let before_ones = x.count_ones();
757                    let shifted = (**x) << rhs;
758                    let after_ones = x.count_ones();
759                    if before_ones != after_ones {
760                        halt2!(span, "shl");
761                    }
762                    shifted.into()
763                }
764                SvmLiteralParam::U64(x) => {
765                    let before_ones = x.count_ones();
766                    let shifted = (**x) << rhs;
767                    let after_ones = x.count_ones();
768                    if before_ones != after_ones {
769                        halt2!(span, "shl");
770                    }
771                    shifted.into()
772                }
773                SvmLiteralParam::U128(x) => {
774                    let before_ones = x.count_ones();
775                    let shifted = (**x) << rhs;
776                    let after_ones = x.count_ones();
777                    if before_ones != after_ones {
778                        halt2!(span, "shl");
779                    }
780                    shifted.into()
781                }
782                SvmLiteralParam::I8(x) => {
783                    let before_ones = x.count_ones();
784                    let shifted = (**x) << rhs;
785                    let after_ones = x.count_ones();
786                    if before_ones != after_ones {
787                        halt2!(span, "shl");
788                    }
789                    shifted.into()
790                }
791                SvmLiteralParam::I16(x) => {
792                    let before_ones = x.count_ones();
793                    let shifted = (**x) << rhs;
794                    let after_ones = x.count_ones();
795                    if before_ones != after_ones {
796                        halt2!(span, "shl");
797                    }
798                    shifted.into()
799                }
800                SvmLiteralParam::I32(x) => {
801                    let before_ones = x.count_ones();
802                    let shifted = (**x) << rhs;
803                    let after_ones = x.count_ones();
804                    if before_ones != after_ones {
805                        halt2!(span, "shl");
806                    }
807                    shifted.into()
808                }
809                SvmLiteralParam::I64(x) => {
810                    let before_ones = x.count_ones();
811                    let shifted = (**x) << rhs;
812                    let after_ones = x.count_ones();
813                    if before_ones != after_ones {
814                        halt2!(span, "shl");
815                    }
816                    shifted.into()
817                }
818                SvmLiteralParam::I128(x) => {
819                    let before_ones = x.count_ones();
820                    let shifted = (**x) << rhs;
821                    let after_ones = x.count_ones();
822                    if before_ones != after_ones {
823                        halt2!(span, "shl");
824                    }
825                    shifted.into()
826                }
827                _ => halt2!(span, "Type error"),
828            }
829        }
830
831        BinaryOperation::ShlWrapped => {
832            let rhs: u32 = match rhs {
833                SvmLiteralParam::U8(y) => (**y).into(),
834                SvmLiteralParam::U16(y) => (**y).into(),
835                SvmLiteralParam::U32(y) => **y,
836                _ => halt2!(span, "Type error"),
837            };
838            match lhs {
839                SvmLiteralParam::U8(x) => x.wrapping_shl(rhs).into(),
840                SvmLiteralParam::U16(x) => x.wrapping_shl(rhs).into(),
841                SvmLiteralParam::U32(x) => x.wrapping_shl(rhs).into(),
842                SvmLiteralParam::U64(x) => x.wrapping_shl(rhs).into(),
843                SvmLiteralParam::U128(x) => x.wrapping_shl(rhs).into(),
844                SvmLiteralParam::I8(x) => x.wrapping_shl(rhs).into(),
845                SvmLiteralParam::I16(x) => x.wrapping_shl(rhs).into(),
846                SvmLiteralParam::I32(x) => x.wrapping_shl(rhs).into(),
847                SvmLiteralParam::I64(x) => x.wrapping_shl(rhs).into(),
848                SvmLiteralParam::I128(x) => x.wrapping_shl(rhs).into(),
849                _ => halt2!(span, "Type error"),
850            }
851        }
852
853        BinaryOperation::Shr => {
854            let rhs: u32 = match rhs {
855                SvmLiteralParam::U8(y) => (**y).into(),
856                SvmLiteralParam::U16(y) => (**y).into(),
857                SvmLiteralParam::U32(y) => **y,
858                _ => halt2!(span, "Type error"),
859            };
860
861            match lhs {
862                SvmLiteralParam::U8(_) | SvmLiteralParam::I8(_) if rhs >= 8 => halt2!(span, "shr overflow"),
863                SvmLiteralParam::U16(_) | SvmLiteralParam::I16(_) if rhs >= 16 => halt2!(span, "shr overflow"),
864                SvmLiteralParam::U32(_) | SvmLiteralParam::I32(_) if rhs >= 32 => halt2!(span, "shr overflow"),
865                SvmLiteralParam::U64(_) | SvmLiteralParam::I64(_) if rhs >= 64 => halt2!(span, "shr overflow"),
866                SvmLiteralParam::U128(_) | SvmLiteralParam::I128(_) if rhs >= 128 => halt2!(span, "shr overflow"),
867                SvmLiteralParam::U8(x) => (**x >> rhs).into(),
868                SvmLiteralParam::U16(x) => (**x >> rhs).into(),
869                SvmLiteralParam::U32(x) => (**x >> rhs).into(),
870                SvmLiteralParam::U64(x) => (**x >> rhs).into(),
871                SvmLiteralParam::U128(x) => (**x >> rhs).into(),
872                SvmLiteralParam::I8(x) => (**x >> rhs).into(),
873                SvmLiteralParam::I16(x) => (**x >> rhs).into(),
874                SvmLiteralParam::I32(x) => (**x >> rhs).into(),
875                SvmLiteralParam::I64(x) => (**x >> rhs).into(),
876                SvmLiteralParam::I128(x) => (**x >> rhs).into(),
877                _ => tc_fail2!(),
878            }
879        }
880
881        BinaryOperation::ShrWrapped => {
882            let rhs: u32 = match rhs {
883                SvmLiteralParam::U8(y) => (**y).into(),
884                SvmLiteralParam::U16(y) => (**y).into(),
885                SvmLiteralParam::U32(y) => **y,
886                _ => halt2!(span, "Type error"),
887            };
888
889            match lhs {
890                SvmLiteralParam::U8(x) => (x.wrapping_shr(rhs)).into(),
891                SvmLiteralParam::U16(x) => (x.wrapping_shr(rhs)).into(),
892                SvmLiteralParam::U32(x) => (x.wrapping_shr(rhs)).into(),
893                SvmLiteralParam::U64(x) => (x.wrapping_shr(rhs)).into(),
894                SvmLiteralParam::U128(x) => (x.wrapping_shr(rhs)).into(),
895                SvmLiteralParam::I8(x) => (x.wrapping_shr(rhs)).into(),
896                SvmLiteralParam::I16(x) => (x.wrapping_shr(rhs)).into(),
897                SvmLiteralParam::I32(x) => (x.wrapping_shr(rhs)).into(),
898                SvmLiteralParam::I64(x) => (x.wrapping_shr(rhs)).into(),
899                SvmLiteralParam::I128(x) => (x.wrapping_shr(rhs)).into(),
900                _ => halt2!(span, "Type error"),
901            }
902        }
903
904        BinaryOperation::Sub => {
905            let Some(value) = (match (lhs, rhs) {
906                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x).checked_sub(**y).map(|z| z.into()),
907                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x).checked_sub(**y).map(|z| z.into()),
908                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x).checked_sub(**y).map(|z| z.into()),
909                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x).checked_sub(**y).map(|z| z.into()),
910                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x).checked_sub(**y).map(|z| z.into()),
911                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x).checked_sub(**y).map(|z| z.into()),
912                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x).checked_sub(**y).map(|z| z.into()),
913                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x).checked_sub(**y).map(|z| z.into()),
914                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x).checked_sub(**y).map(|z| z.into()),
915                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x).checked_sub(**y).map(|z| z.into()),
916                (SvmLiteralParam::Group(x), SvmLiteralParam::Group(y)) => Some((*x - *y).into()),
917                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => Some((*x - *y).into()),
918                _ => halt2!(span, "Type error"),
919            }) else {
920                halt2!(span, "sub overflow");
921            };
922            value
923        }
924
925        BinaryOperation::SubWrapped => match (lhs, rhs) {
926            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x).wrapping_sub(**y).into(),
927            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x).wrapping_sub(**y).into(),
928            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x).wrapping_sub(**y).into(),
929            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x).wrapping_sub(**y).into(),
930            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x).wrapping_sub(**y).into(),
931            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x).wrapping_sub(**y).into(),
932            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x).wrapping_sub(**y).into(),
933            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x).wrapping_sub(**y).into(),
934            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x).wrapping_sub(**y).into(),
935            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x).wrapping_sub(**y).into(),
936            _ => halt2!(span, "Type error"),
937        },
938        BinaryOperation::Xor => match (lhs, rhs) {
939            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x ^ **y).into(),
940            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x ^ **y).into(),
941            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x ^ **y).into(),
942            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x ^ **y).into(),
943            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x ^ **y).into(),
944            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x ^ **y).into(),
945            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x ^ **y).into(),
946            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x ^ **y).into(),
947            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x ^ **y).into(),
948            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x ^ **y).into(),
949            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x ^ **y).into(),
950            _ => halt2!(span, "Type error"),
951        },
952    };
953
954    Ok(value)
955}
956
957// SnarkVM will not parse fields, groups, or scalars with leading zeros, so we strip them out.
958fn prepare_snarkvm_string(s: &str, suffix: &str) -> String {
959    // If there's a `-`, separate it from the rest of the string.
960    let (neg, rest) = s.strip_prefix("-").map(|rest| ("-", rest)).unwrap_or(("", s));
961    // Remove leading zeros.
962    let mut rest = rest.trim_start_matches('0');
963    if rest.is_empty() {
964        rest = "0";
965    }
966    format!("{neg}{rest}{suffix}")
967}