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::String(..) => tc_fail2!(),
206    })
207}
208
209/// Resolves an unsuffixed operand for a unary operation by inferring its type based on the operation and an optional
210/// expected type. Uses predefined types (`Field` or `Group`) for specific operations, otherwise defaults to the expected
211/// type if available. Returns the resolved `Value` or an error if type resolution fails.
212fn resolve_unsuffixed_unary_op_operand(
213    val: &Value,
214    op: &UnaryOperation,
215    expected_ty: &Option<Type>,
216    span: &Span,
217) -> Result<Value> {
218    match op {
219        UnaryOperation::Inverse | UnaryOperation::Square | UnaryOperation::SquareRoot => {
220            // These ops only take a `field` and return a `field`
221            val.resolve_if_unsuffixed(&Some(Type::Field), *span)
222        }
223        UnaryOperation::ToXCoordinate | UnaryOperation::ToYCoordinate => {
224            // These ops only take a `Group`
225            val.resolve_if_unsuffixed(&Some(Type::Group), *span)
226        }
227        _ => {
228            // All other unary ops take the same type as the their return type
229            val.resolve_if_unsuffixed(expected_ty, *span)
230        }
231    }
232}
233
234/// Evaluate a unary operation.
235pub fn evaluate_unary(span: Span, op: UnaryOperation, value: &Value, expected_ty: &Option<Type>) -> Result<Value> {
236    let value = resolve_unsuffixed_unary_op_operand(value, &op, expected_ty, &span)?;
237    let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(literal, ..))) = &value.contents else {
238        halt2!(span, "Type error");
239    };
240    let value_result: Value = match op {
241        UnaryOperation::Abs => match literal {
242            SvmLiteralParam::I8(x) => {
243                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overflow"))?.into()
244            }
245            SvmLiteralParam::I16(x) => {
246                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
247            }
248            SvmLiteralParam::I32(x) => {
249                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
250            }
251            SvmLiteralParam::I64(x) => {
252                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
253            }
254            SvmLiteralParam::I128(x) => {
255                x.checked_abs().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "abs overlfow"))?.into()
256            }
257            _ => halt2!(span, "Type error"),
258        },
259        UnaryOperation::AbsWrapped => match literal {
260            SvmLiteralParam::I8(x) => (x.unsigned_abs() as i8).into(),
261            SvmLiteralParam::I16(x) => (x.unsigned_abs() as i16).into(),
262            SvmLiteralParam::I32(x) => (x.unsigned_abs() as i32).into(),
263            SvmLiteralParam::I64(x) => (x.unsigned_abs() as i64).into(),
264            SvmLiteralParam::I128(x) => (x.unsigned_abs() as i128).into(),
265            _ => halt2!(span, "Type error"),
266        },
267        UnaryOperation::Double => match literal {
268            SvmLiteralParam::Field(x) => <Field as Double>::double(x).into(),
269            SvmLiteralParam::Group(x) => <Group as Double>::double(x).into(),
270            _ => halt2!(span, "Type error"),
271        },
272        UnaryOperation::Inverse => match literal {
273            SvmLiteralParam::Field(x) => {
274                let Ok(y) = x.inverse() else {
275                    halt2!(span, "attempt to invert 0field");
276                };
277                y.into()
278            }
279            _ => halt2!(span, "Can only invert fields"),
280        },
281        UnaryOperation::Negate => match literal {
282            SvmLiteralParam::I8(x) => {
283                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
284            }
285            SvmLiteralParam::I16(x) => {
286                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
287            }
288            SvmLiteralParam::I32(x) => {
289                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
290            }
291            SvmLiteralParam::I64(x) => {
292                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
293            }
294            SvmLiteralParam::I128(x) => {
295                x.checked_neg().ok_or_else::<InterpreterHalt, _>(|| fail2!(span, "negation overflow"))?.into()
296            }
297            SvmLiteralParam::Group(x) => (-*x).into(),
298            SvmLiteralParam::Field(x) => (-*x).into(),
299            _ => halt2!(span, "Type error"),
300        },
301        UnaryOperation::Not => match literal {
302            SvmLiteralParam::Boolean(x) => (!**x).into(),
303            SvmLiteralParam::U8(x) => (!**x).into(),
304            SvmLiteralParam::U16(x) => (!**x).into(),
305            SvmLiteralParam::U32(x) => (!**x).into(),
306            SvmLiteralParam::U64(x) => (!**x).into(),
307            SvmLiteralParam::U128(x) => (!**x).into(),
308            SvmLiteralParam::I8(x) => (!**x).into(),
309            SvmLiteralParam::I16(x) => (!**x).into(),
310            SvmLiteralParam::I32(x) => (!**x).into(),
311            SvmLiteralParam::I64(x) => (!**x).into(),
312            SvmLiteralParam::I128(x) => (!**x).into(),
313            _ => halt2!(span, "Type error"),
314        },
315        UnaryOperation::Square => match literal {
316            SvmLiteralParam::Field(x) => x.square().into(),
317            _ => halt2!(span, "Can only square fields"),
318        },
319        UnaryOperation::SquareRoot => match literal {
320            SvmLiteralParam::Field(x) => {
321                x.square_root().map_err::<InterpreterHalt, _>(|e| fail2!(span, "square root failure: {e}"))?.into()
322            }
323            _ => halt2!(span, "Can only apply square_root to fields"),
324        },
325        UnaryOperation::ToXCoordinate => match literal {
326            SvmLiteral::Group(x) => x.to_x_coordinate().into(),
327            _ => tc_fail2!(),
328        },
329        UnaryOperation::ToYCoordinate => match literal {
330            SvmLiteral::Group(x) => x.to_y_coordinate().into(),
331            _ => tc_fail2!(),
332        },
333    };
334
335    Ok(value_result)
336}
337
338/// Resolves unsuffixed numeric operands for binary operations by inferring types based on the other operand, the
339/// operation type, and an optional expected type. Handles special cases for multiplication and exponentiation with
340/// additional logic for `Group`, `Scalar`, and `Field` type inference. Ensures that both operands are resolved to
341/// compatible types before evaluation. Returns a tuple of resolved `Value`s or an error if resolution fails.
342fn resolve_unsuffixed_binary_op_operands(
343    lhs: &Value,
344    rhs: &Value,
345    op: &BinaryOperation,
346    expected_ty: &Option<Type>,
347    span: &Span,
348) -> Result<(Value, Value)> {
349    use Type::*;
350
351    let lhs_ty = lhs.get_numeric_type();
352    let rhs_ty = rhs.get_numeric_type();
353
354    Ok(match op {
355        BinaryOperation::Mul => {
356            // For a `Mul`, if on operand is a Scalar, then the other must ba a `Group`. Otherwise, both ops must have
357            // the same type as the return type of the multiplication.
358            let lhs = match rhs_ty {
359                Some(Group) => lhs.resolve_if_unsuffixed(&Some(Scalar), *span)?,
360                Some(Scalar) => lhs.resolve_if_unsuffixed(&Some(Group), *span)?,
361                _ => lhs.resolve_if_unsuffixed(&rhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
362            };
363
364            let rhs = match lhs_ty {
365                Some(Group) => rhs.resolve_if_unsuffixed(&Some(Scalar), *span)?,
366                Some(Scalar) => rhs.resolve_if_unsuffixed(&Some(Group), *span)?,
367                _ => rhs.resolve_if_unsuffixed(&lhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
368            };
369
370            (lhs, rhs)
371        }
372        BinaryOperation::Pow => {
373            // For a `Pow`, if one operand is a `Field`, then the other must also be a `Field.
374            // Otherwise, only the `lhs` must match the return type.
375            let lhs_resolved = lhs
376                .resolve_if_unsuffixed(&rhs_ty.filter(|ty| matches!(ty, Type::Field)), *span)?
377                .resolve_if_unsuffixed(expected_ty, *span)?;
378
379            let rhs_resolved = rhs.resolve_if_unsuffixed(&lhs_ty.filter(|ty| matches!(ty, Type::Field)), *span)?;
380
381            (lhs_resolved, rhs_resolved)
382        }
383        _ => (
384            lhs.resolve_if_unsuffixed(&rhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
385            rhs.resolve_if_unsuffixed(&lhs_ty, *span)?.resolve_if_unsuffixed(expected_ty, *span)?,
386        ),
387    })
388}
389
390/// Evaluate a binary operation.
391pub fn evaluate_binary(
392    span: Span,
393    op: BinaryOperation,
394    lhs: &Value,
395    rhs: &Value,
396    expected_ty: &Option<Type>,
397) -> Result<Value> {
398    let (lhs, rhs) = resolve_unsuffixed_binary_op_operands(lhs, rhs, &op, expected_ty, &span)?;
399
400    match op {
401        BinaryOperation::Eq => return lhs.eq(&rhs).map(|x| x.into()),
402        BinaryOperation::Neq => return lhs.eq(&rhs).map(|x| (!x).into()),
403        _ => {}
404    }
405
406    let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(lhs, ..))) = &lhs.contents else {
407        halt2!(span, "Type error");
408    };
409    let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(rhs, ..))) = &rhs.contents else {
410        halt2!(span, "Type error");
411    };
412    let value = match op {
413        BinaryOperation::Add => {
414            let Some(value): Option<Value> = (match (lhs, rhs) {
415                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x).checked_add(**y).map(|z| z.into()),
416                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x).checked_add(**y).map(|z| z.into()),
417                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x).checked_add(**y).map(|z| z.into()),
418                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x).checked_add(**y).map(|z| z.into()),
419                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x).checked_add(**y).map(|z| z.into()),
420                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x).checked_add(**y).map(|z| z.into()),
421                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x).checked_add(**y).map(|z| z.into()),
422                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x).checked_add(**y).map(|z| z.into()),
423                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x).checked_add(**y).map(|z| z.into()),
424                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x).checked_add(**y).map(|z| z.into()),
425                (SvmLiteralParam::Group(x), SvmLiteralParam::Group(y)) => Some((*x + y).into()),
426                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => Some((*x + y).into()),
427                (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => Some((*x + y).into()),
428                _ => halt2!(span, "Type error"),
429            }) else {
430                halt2!(span, "add overflow");
431            };
432            value
433        }
434        BinaryOperation::AddWrapped => match (lhs, rhs) {
435            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x).wrapping_add(**y).into(),
436            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x).wrapping_add(**y).into(),
437            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x).wrapping_add(**y).into(),
438            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x).wrapping_add(**y).into(),
439            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x).wrapping_add(**y).into(),
440            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x).wrapping_add(**y).into(),
441            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x).wrapping_add(**y).into(),
442            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x).wrapping_add(**y).into(),
443            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x).wrapping_add(**y).into(),
444            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x).wrapping_add(**y).into(),
445            _ => halt2!(span, "Type error"),
446        },
447        BinaryOperation::And => match (lhs, rhs) {
448            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x && **y).into(),
449            _ => halt2!(span, "Type error"),
450        },
451        BinaryOperation::BitwiseAnd => match (lhs, rhs) {
452            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x & **y).into(),
453            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x & **y).into(),
454            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x & **y).into(),
455            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x & **y).into(),
456            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x & **y).into(),
457            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x & **y).into(),
458            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x & **y).into(),
459            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x & **y).into(),
460            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x & **y).into(),
461            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x & **y).into(),
462            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x & **y).into(),
463            _ => halt2!(span, "Type error"),
464        },
465        BinaryOperation::Div => {
466            let Some(value) = (match (lhs, rhs) {
467                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x).checked_div(**y).map(|z| z.into()),
468                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x).checked_div(**y).map(|z| z.into()),
469                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x).checked_div(**y).map(|z| z.into()),
470                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x).checked_div(**y).map(|z| z.into()),
471                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x).checked_div(**y).map(|z| z.into()),
472                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x).checked_div(**y).map(|z| z.into()),
473                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x).checked_div(**y).map(|z| z.into()),
474                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x).checked_div(**y).map(|z| z.into()),
475                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x).checked_div(**y).map(|z| z.into()),
476                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x).checked_div(**y).map(|z| z.into()),
477                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => y.inverse().map(|y| (*x * y).into()).ok(),
478                _ => halt2!(span, "Type error"),
479            }) else {
480                halt2!(span, "div overflow");
481            };
482            value
483        }
484        BinaryOperation::DivWrapped => match (lhs, rhs) {
485            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
486            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
487            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
488            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
489            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
490            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
491            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
492            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
493            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
494            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) if **y != 0 => (*x).wrapping_div(**y).into(),
495            _ => halt2!(span, "Type error"),
496        },
497        BinaryOperation::Eq => unreachable!("This case was handled above"),
498        BinaryOperation::Gte => match (lhs, rhs) {
499            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x >= *y).into(),
500            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x >= *y).into(),
501            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x >= *y).into(),
502            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x >= *y).into(),
503            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x >= *y).into(),
504            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x >= *y).into(),
505            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x >= *y).into(),
506            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x >= *y).into(),
507            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x >= *y).into(),
508            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x >= *y).into(),
509            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x >= *y).into(),
510            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x >= *y).into(),
511            _ => halt2!(span, "Type error"),
512        },
513        BinaryOperation::Gt => match (lhs, rhs) {
514            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x > *y).into(),
515            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x > *y).into(),
516            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x > *y).into(),
517            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x > *y).into(),
518            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x > *y).into(),
519            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x > *y).into(),
520            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x > *y).into(),
521            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x > *y).into(),
522            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x > *y).into(),
523            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x > *y).into(),
524            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x > *y).into(),
525            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x > *y).into(),
526            _ => halt2!(span, "Type error"),
527        },
528        BinaryOperation::Lte => match (lhs, rhs) {
529            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x <= *y).into(),
530            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x <= *y).into(),
531            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x <= *y).into(),
532            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x <= *y).into(),
533            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x <= *y).into(),
534            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x <= *y).into(),
535            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x <= *y).into(),
536            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x <= *y).into(),
537            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x <= *y).into(),
538            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x <= *y).into(),
539            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x <= *y).into(),
540            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x <= *y).into(),
541            _ => halt2!(span, "Type error"),
542        },
543        BinaryOperation::Lt => match (lhs, rhs) {
544            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (*x < *y).into(),
545            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (*x < *y).into(),
546            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (*x < *y).into(),
547            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (*x < *y).into(),
548            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (*x < *y).into(),
549            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (*x < *y).into(),
550            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (*x < *y).into(),
551            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (*x < *y).into(),
552            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (*x < *y).into(),
553            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (*x < *y).into(),
554            (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => (*x < *y).into(),
555            (SvmLiteralParam::Scalar(x), SvmLiteralParam::Scalar(y)) => (*x < *y).into(),
556            _ => halt2!(span, "Type error"),
557        },
558        BinaryOperation::Mod => {
559            let Some(value) = (match (lhs, rhs) {
560                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => x.checked_rem(**y).map(|z| z.into()),
561                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => x.checked_rem(**y).map(|z| z.into()),
562                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => x.checked_rem(**y).map(|z| z.into()),
563                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => x.checked_rem(**y).map(|z| z.into()),
564                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => x.checked_rem(**y).map(|z| z.into()),
565                _ => halt2!(span, "Type error"),
566            }) else {
567                halt2!(span, "mod overflow");
568            };
569            value
570        }
571        BinaryOperation::Mul => {
572            let Some(value) = (match (lhs, rhs) {
573                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => x.checked_mul(**y).map(|z| z.into()),
574                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => x.checked_mul(**y).map(|z| z.into()),
575                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => x.checked_mul(**y).map(|z| z.into()),
576                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => x.checked_mul(**y).map(|z| z.into()),
577                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => x.checked_mul(**y).map(|z| z.into()),
578                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => x.checked_mul(**y).map(|z| z.into()),
579                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => x.checked_mul(**y).map(|z| z.into()),
580                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => x.checked_mul(**y).map(|z| z.into()),
581                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => x.checked_mul(**y).map(|z| z.into()),
582                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => x.checked_mul(**y).map(|z| z.into()),
583                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => Some((*x * y).into()),
584                (SvmLiteralParam::Group(x), SvmLiteralParam::Scalar(y)) => Some((*x * y).into()),
585                (SvmLiteralParam::Scalar(x), SvmLiteralParam::Group(y)) => Some((*x * y).into()),
586                _ => halt2!(span, "Type error"),
587            }) else {
588                halt2!(span, "mul overflow");
589            };
590            value
591        }
592        BinaryOperation::MulWrapped => match (lhs, rhs) {
593            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => x.wrapping_mul(**y).into(),
594            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => x.wrapping_mul(**y).into(),
595            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => x.wrapping_mul(**y).into(),
596            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => x.wrapping_mul(**y).into(),
597            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => x.wrapping_mul(**y).into(),
598            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => x.wrapping_mul(**y).into(),
599            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => x.wrapping_mul(**y).into(),
600            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => x.wrapping_mul(**y).into(),
601            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => x.wrapping_mul(**y).into(),
602            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => x.wrapping_mul(**y).into(),
603            _ => halt2!(span, "Type error"),
604        },
605
606        BinaryOperation::Nand => match (lhs, rhs) {
607            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (!(**x & **y)).into(),
608            _ => halt2!(span, "Type error"),
609        },
610
611        BinaryOperation::Neq => unreachable!("This case was handled above"),
612
613        BinaryOperation::Nor => match (lhs, rhs) {
614            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (!(**x | **y)).into(),
615            _ => halt2!(span, "Type error"),
616        },
617
618        BinaryOperation::Or => match (lhs, rhs) {
619            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x | **y).into(),
620            _ => halt2!(span, "Type error"),
621        },
622
623        BinaryOperation::BitwiseOr => match (lhs, rhs) {
624            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x | **y).into(),
625            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x | **y).into(),
626            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x | **y).into(),
627            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x | **y).into(),
628            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x | **y).into(),
629            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x | **y).into(),
630            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x | **y).into(),
631            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x | **y).into(),
632            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x | **y).into(),
633            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x | **y).into(),
634            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x | **y).into(),
635            _ => halt2!(span, "Type error"),
636        },
637
638        BinaryOperation::Pow => {
639            if let (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) = (&lhs, &rhs) {
640                x.pow(y).into()
641            } else {
642                let rhs: u32 = match rhs {
643                    SvmLiteralParam::U8(y) => (**y).into(),
644                    SvmLiteralParam::U16(y) => (**y).into(),
645                    SvmLiteralParam::U32(y) => **y,
646                    _ => tc_fail2!(),
647                };
648
649                let Some(value) = (match lhs {
650                    SvmLiteralParam::U8(x) => x.checked_pow(rhs).map(|z| z.into()),
651                    SvmLiteralParam::U16(x) => x.checked_pow(rhs).map(|z| z.into()),
652                    SvmLiteralParam::U32(x) => x.checked_pow(rhs).map(|z| z.into()),
653                    SvmLiteralParam::U64(x) => x.checked_pow(rhs).map(|z| z.into()),
654                    SvmLiteralParam::U128(x) => x.checked_pow(rhs).map(|z| z.into()),
655                    SvmLiteralParam::I8(x) => x.checked_pow(rhs).map(|z| z.into()),
656                    SvmLiteralParam::I16(x) => x.checked_pow(rhs).map(|z| z.into()),
657                    SvmLiteralParam::I32(x) => x.checked_pow(rhs).map(|z| z.into()),
658                    SvmLiteralParam::I64(x) => x.checked_pow(rhs).map(|z| z.into()),
659                    SvmLiteralParam::I128(x) => x.checked_pow(rhs).map(|z| z.into()),
660                    _ => halt2!(span, "Type error"),
661                }) else {
662                    halt2!(span, "pow overflow");
663                };
664                value
665            }
666        }
667        BinaryOperation::PowWrapped => {
668            let rhs: u32 = match rhs {
669                SvmLiteralParam::U8(y) => (**y).into(),
670                SvmLiteralParam::U16(y) => (**y).into(),
671                SvmLiteralParam::U32(y) => **y,
672                _ => halt2!(span, "Type error"),
673            };
674
675            match lhs {
676                SvmLiteralParam::U8(x) => x.wrapping_pow(rhs).into(),
677                SvmLiteralParam::U16(x) => x.wrapping_pow(rhs).into(),
678                SvmLiteralParam::U32(x) => x.wrapping_pow(rhs).into(),
679                SvmLiteralParam::U64(x) => x.wrapping_pow(rhs).into(),
680                SvmLiteralParam::U128(x) => x.wrapping_pow(rhs).into(),
681                SvmLiteralParam::I8(x) => x.wrapping_pow(rhs).into(),
682                SvmLiteralParam::I16(x) => x.wrapping_pow(rhs).into(),
683                SvmLiteralParam::I32(x) => x.wrapping_pow(rhs).into(),
684                SvmLiteralParam::I64(x) => x.wrapping_pow(rhs).into(),
685                SvmLiteralParam::I128(x) => x.wrapping_pow(rhs).into(),
686                _ => halt2!(span, "Type error"),
687            }
688        }
689
690        BinaryOperation::Rem => {
691            let Some(value) = (match (lhs, rhs) {
692                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x).checked_rem(**y).map(|z| z.into()),
693                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x).checked_rem(**y).map(|z| z.into()),
694                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x).checked_rem(**y).map(|z| z.into()),
695                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x).checked_rem(**y).map(|z| z.into()),
696                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x).checked_rem(**y).map(|z| z.into()),
697                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x).checked_rem(**y).map(|z| z.into()),
698                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x).checked_rem(**y).map(|z| z.into()),
699                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x).checked_rem(**y).map(|z| z.into()),
700                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x).checked_rem(**y).map(|z| z.into()),
701                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x).checked_rem(**y).map(|z| z.into()),
702                _ => halt2!(span, "Type error"),
703            }) else {
704                halt2!(span, "rem error");
705            };
706            value
707        }
708
709        BinaryOperation::RemWrapped => match (lhs, rhs) {
710            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
711            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
712            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
713            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
714            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
715            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
716            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
717            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
718            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
719            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) if **y != 0 => (*x).wrapping_rem(**y).into(),
720            _ => halt2!(span, "Type error"),
721        },
722
723        BinaryOperation::Shl => {
724            let rhs: u32 = match rhs {
725                SvmLiteralParam::U8(y) => (**y).into(),
726                SvmLiteralParam::U16(y) => (**y).into(),
727                SvmLiteralParam::U32(y) => **y,
728                _ => halt2!(span, "Type error"),
729            };
730            match lhs {
731                SvmLiteralParam::U8(_) | SvmLiteralParam::I8(_) if rhs >= 8 => halt2!(span, "shl overflow"),
732                SvmLiteralParam::U16(_) | SvmLiteralParam::I16(_) if rhs >= 16 => halt2!(span, "shl overflow"),
733                SvmLiteralParam::U32(_) | SvmLiteralParam::I32(_) if rhs >= 32 => halt2!(span, "shl overflow"),
734                SvmLiteralParam::U64(_) | SvmLiteralParam::I64(_) if rhs >= 64 => halt2!(span, "shl overflow"),
735                SvmLiteralParam::U128(_) | SvmLiteralParam::I128(_) if rhs >= 128 => halt2!(span, "shl overflow"),
736                SvmLiteralParam::U8(x) => {
737                    let before_ones = x.count_ones();
738                    let shifted = (**x) << rhs;
739                    let after_ones = x.count_ones();
740                    if before_ones != after_ones {
741                        halt2!(span, "shl");
742                    }
743                    shifted.into()
744                }
745                SvmLiteralParam::U16(x) => {
746                    let before_ones = x.count_ones();
747                    let shifted = (**x) << rhs;
748                    let after_ones = x.count_ones();
749                    if before_ones != after_ones {
750                        halt2!(span, "shl");
751                    }
752                    shifted.into()
753                }
754                SvmLiteralParam::U32(x) => {
755                    let before_ones = x.count_ones();
756                    let shifted = (**x) << rhs;
757                    let after_ones = x.count_ones();
758                    if before_ones != after_ones {
759                        halt2!(span, "shl");
760                    }
761                    shifted.into()
762                }
763                SvmLiteralParam::U64(x) => {
764                    let before_ones = x.count_ones();
765                    let shifted = (**x) << rhs;
766                    let after_ones = x.count_ones();
767                    if before_ones != after_ones {
768                        halt2!(span, "shl");
769                    }
770                    shifted.into()
771                }
772                SvmLiteralParam::U128(x) => {
773                    let before_ones = x.count_ones();
774                    let shifted = (**x) << rhs;
775                    let after_ones = x.count_ones();
776                    if before_ones != after_ones {
777                        halt2!(span, "shl");
778                    }
779                    shifted.into()
780                }
781                SvmLiteralParam::I8(x) => {
782                    let before_ones = x.count_ones();
783                    let shifted = (**x) << rhs;
784                    let after_ones = x.count_ones();
785                    if before_ones != after_ones {
786                        halt2!(span, "shl");
787                    }
788                    shifted.into()
789                }
790                SvmLiteralParam::I16(x) => {
791                    let before_ones = x.count_ones();
792                    let shifted = (**x) << rhs;
793                    let after_ones = x.count_ones();
794                    if before_ones != after_ones {
795                        halt2!(span, "shl");
796                    }
797                    shifted.into()
798                }
799                SvmLiteralParam::I32(x) => {
800                    let before_ones = x.count_ones();
801                    let shifted = (**x) << rhs;
802                    let after_ones = x.count_ones();
803                    if before_ones != after_ones {
804                        halt2!(span, "shl");
805                    }
806                    shifted.into()
807                }
808                SvmLiteralParam::I64(x) => {
809                    let before_ones = x.count_ones();
810                    let shifted = (**x) << rhs;
811                    let after_ones = x.count_ones();
812                    if before_ones != after_ones {
813                        halt2!(span, "shl");
814                    }
815                    shifted.into()
816                }
817                SvmLiteralParam::I128(x) => {
818                    let before_ones = x.count_ones();
819                    let shifted = (**x) << rhs;
820                    let after_ones = x.count_ones();
821                    if before_ones != after_ones {
822                        halt2!(span, "shl");
823                    }
824                    shifted.into()
825                }
826                _ => halt2!(span, "Type error"),
827            }
828        }
829
830        BinaryOperation::ShlWrapped => {
831            let rhs: u32 = match rhs {
832                SvmLiteralParam::U8(y) => (**y).into(),
833                SvmLiteralParam::U16(y) => (**y).into(),
834                SvmLiteralParam::U32(y) => **y,
835                _ => halt2!(span, "Type error"),
836            };
837            match lhs {
838                SvmLiteralParam::U8(x) => x.wrapping_shl(rhs).into(),
839                SvmLiteralParam::U16(x) => x.wrapping_shl(rhs).into(),
840                SvmLiteralParam::U32(x) => x.wrapping_shl(rhs).into(),
841                SvmLiteralParam::U64(x) => x.wrapping_shl(rhs).into(),
842                SvmLiteralParam::U128(x) => x.wrapping_shl(rhs).into(),
843                SvmLiteralParam::I8(x) => x.wrapping_shl(rhs).into(),
844                SvmLiteralParam::I16(x) => x.wrapping_shl(rhs).into(),
845                SvmLiteralParam::I32(x) => x.wrapping_shl(rhs).into(),
846                SvmLiteralParam::I64(x) => x.wrapping_shl(rhs).into(),
847                SvmLiteralParam::I128(x) => x.wrapping_shl(rhs).into(),
848                _ => halt2!(span, "Type error"),
849            }
850        }
851
852        BinaryOperation::Shr => {
853            let rhs: u32 = match rhs {
854                SvmLiteralParam::U8(y) => (**y).into(),
855                SvmLiteralParam::U16(y) => (**y).into(),
856                SvmLiteralParam::U32(y) => **y,
857                _ => halt2!(span, "Type error"),
858            };
859
860            match lhs {
861                SvmLiteralParam::U8(_) | SvmLiteralParam::I8(_) if rhs >= 8 => halt2!(span, "shr overflow"),
862                SvmLiteralParam::U16(_) | SvmLiteralParam::I16(_) if rhs >= 16 => halt2!(span, "shr overflow"),
863                SvmLiteralParam::U32(_) | SvmLiteralParam::I32(_) if rhs >= 32 => halt2!(span, "shr overflow"),
864                SvmLiteralParam::U64(_) | SvmLiteralParam::I64(_) if rhs >= 64 => halt2!(span, "shr overflow"),
865                SvmLiteralParam::U128(_) | SvmLiteralParam::I128(_) if rhs >= 128 => halt2!(span, "shr overflow"),
866                SvmLiteralParam::U8(x) => (**x >> rhs).into(),
867                SvmLiteralParam::U16(x) => (**x >> rhs).into(),
868                SvmLiteralParam::U32(x) => (**x >> rhs).into(),
869                SvmLiteralParam::U64(x) => (**x >> rhs).into(),
870                SvmLiteralParam::U128(x) => (**x >> rhs).into(),
871                SvmLiteralParam::I8(x) => (**x >> rhs).into(),
872                SvmLiteralParam::I16(x) => (**x >> rhs).into(),
873                SvmLiteralParam::I32(x) => (**x >> rhs).into(),
874                SvmLiteralParam::I64(x) => (**x >> rhs).into(),
875                SvmLiteralParam::I128(x) => (**x >> rhs).into(),
876                _ => tc_fail2!(),
877            }
878        }
879
880        BinaryOperation::ShrWrapped => {
881            let rhs: u32 = match rhs {
882                SvmLiteralParam::U8(y) => (**y).into(),
883                SvmLiteralParam::U16(y) => (**y).into(),
884                SvmLiteralParam::U32(y) => **y,
885                _ => halt2!(span, "Type error"),
886            };
887
888            match lhs {
889                SvmLiteralParam::U8(x) => (x.wrapping_shr(rhs)).into(),
890                SvmLiteralParam::U16(x) => (x.wrapping_shr(rhs)).into(),
891                SvmLiteralParam::U32(x) => (x.wrapping_shr(rhs)).into(),
892                SvmLiteralParam::U64(x) => (x.wrapping_shr(rhs)).into(),
893                SvmLiteralParam::U128(x) => (x.wrapping_shr(rhs)).into(),
894                SvmLiteralParam::I8(x) => (x.wrapping_shr(rhs)).into(),
895                SvmLiteralParam::I16(x) => (x.wrapping_shr(rhs)).into(),
896                SvmLiteralParam::I32(x) => (x.wrapping_shr(rhs)).into(),
897                SvmLiteralParam::I64(x) => (x.wrapping_shr(rhs)).into(),
898                SvmLiteralParam::I128(x) => (x.wrapping_shr(rhs)).into(),
899                _ => halt2!(span, "Type error"),
900            }
901        }
902
903        BinaryOperation::Sub => {
904            let Some(value) = (match (lhs, rhs) {
905                (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x).checked_sub(**y).map(|z| z.into()),
906                (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x).checked_sub(**y).map(|z| z.into()),
907                (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x).checked_sub(**y).map(|z| z.into()),
908                (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x).checked_sub(**y).map(|z| z.into()),
909                (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x).checked_sub(**y).map(|z| z.into()),
910                (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x).checked_sub(**y).map(|z| z.into()),
911                (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x).checked_sub(**y).map(|z| z.into()),
912                (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x).checked_sub(**y).map(|z| z.into()),
913                (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x).checked_sub(**y).map(|z| z.into()),
914                (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x).checked_sub(**y).map(|z| z.into()),
915                (SvmLiteralParam::Group(x), SvmLiteralParam::Group(y)) => Some((*x - *y).into()),
916                (SvmLiteralParam::Field(x), SvmLiteralParam::Field(y)) => Some((*x - *y).into()),
917                _ => halt2!(span, "Type error"),
918            }) else {
919                halt2!(span, "sub overflow");
920            };
921            value
922        }
923
924        BinaryOperation::SubWrapped => match (lhs, rhs) {
925            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x).wrapping_sub(**y).into(),
926            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x).wrapping_sub(**y).into(),
927            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x).wrapping_sub(**y).into(),
928            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x).wrapping_sub(**y).into(),
929            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x).wrapping_sub(**y).into(),
930            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x).wrapping_sub(**y).into(),
931            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x).wrapping_sub(**y).into(),
932            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x).wrapping_sub(**y).into(),
933            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x).wrapping_sub(**y).into(),
934            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x).wrapping_sub(**y).into(),
935            _ => halt2!(span, "Type error"),
936        },
937        BinaryOperation::Xor => match (lhs, rhs) {
938            (SvmLiteralParam::Boolean(x), SvmLiteralParam::Boolean(y)) => (**x ^ **y).into(),
939            (SvmLiteralParam::U8(x), SvmLiteralParam::U8(y)) => (**x ^ **y).into(),
940            (SvmLiteralParam::U16(x), SvmLiteralParam::U16(y)) => (**x ^ **y).into(),
941            (SvmLiteralParam::U32(x), SvmLiteralParam::U32(y)) => (**x ^ **y).into(),
942            (SvmLiteralParam::U64(x), SvmLiteralParam::U64(y)) => (**x ^ **y).into(),
943            (SvmLiteralParam::U128(x), SvmLiteralParam::U128(y)) => (**x ^ **y).into(),
944            (SvmLiteralParam::I8(x), SvmLiteralParam::I8(y)) => (**x ^ **y).into(),
945            (SvmLiteralParam::I16(x), SvmLiteralParam::I16(y)) => (**x ^ **y).into(),
946            (SvmLiteralParam::I32(x), SvmLiteralParam::I32(y)) => (**x ^ **y).into(),
947            (SvmLiteralParam::I64(x), SvmLiteralParam::I64(y)) => (**x ^ **y).into(),
948            (SvmLiteralParam::I128(x), SvmLiteralParam::I128(y)) => (**x ^ **y).into(),
949            _ => halt2!(span, "Type error"),
950        },
951    };
952
953    Ok(value)
954}
955
956// SnarkVM will not parse fields, groups, or scalars with leading zeros, so we strip them out.
957fn prepare_snarkvm_string(s: &str, suffix: &str) -> String {
958    // If there's a `-`, separate it from the rest of the string.
959    let (neg, rest) = s.strip_prefix("-").map(|rest| ("-", rest)).unwrap_or(("", s));
960    // Remove leading zeros.
961    let mut rest = rest.trim_start_matches('0');
962    if rest.is_empty() {
963        rest = "0";
964    }
965    format!("{neg}{rest}{suffix}")
966}