/ compiler / ast / src / interpreter_value / evaluate.rs
evaluate.rs
  1  // Copyright (C) 2019-2025 ADnet Contributors
  2  // This file is part of the ADL library.
  3  
  4  // The ADL 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 ADL 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 ADL library. If not, see <https://www.gnu.org/licenses/>.
 16  
 17  use snarkvm::prelude::{Double, Inverse as _, Pow as _, ProgramID, Square as _, SquareRoot as _};
 18  
 19  use adl_errors::{InterpreterHalt, Result};
 20  use adl_span::Span;
 21  
 22  use 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  
 36  use super::*;
 37  
 38  impl 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  
139  pub 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(".alpha") || s.ends_with(".delta") {
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(s) => Value::make_string(s.clone()),
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.
213  fn 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.
236  pub 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.
343  fn 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.
392  pub 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.
958  fn 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  }