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 }