diff --git a/Cargo.lock b/Cargo.lock index 3f782059c7..99229123a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1576,6 +1576,7 @@ dependencies = [ "rand_chacha", "snarkvm", "snarkvm-circuit", + "snarkvm-synthesizer-program", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 720c02abc9..adf993ca55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,7 +111,6 @@ default-features = false version = "1.11.1" [workspace.dependencies.snarkvm] -# path = "../SnarkVM" version = "1.0.0" [workspace.dependencies.serde] diff --git a/interpreter/Cargo.toml b/interpreter/Cargo.toml index d0ecb8da2a..ad56279674 100644 --- a/interpreter/Cargo.toml +++ b/interpreter/Cargo.toml @@ -18,11 +18,14 @@ license = "GPL-3.0" edition = "2021" rust-version = "1.82.0" +[dependencies.snarkvm] +workspace = true + [dependencies.snarkvm-circuit] version = "1.0.0" -[dependencies.snarkvm] -workspace = true +[dependencies.snarkvm-synthesizer-program] +version = "1.0.0" [dependencies.leo-ast] workspace = true diff --git a/interpreter/src/cursor.rs b/interpreter/src/cursor.rs index 9d203c7263..26d2ec531f 100644 --- a/interpreter/src/cursor.rs +++ b/interpreter/src/cursor.rs @@ -38,7 +38,10 @@ use leo_span::{Span, Symbol, sym}; use snarkvm::prelude::{ CastLossy as _, + Closure as SvmClosure, Double as _, + Finalize as SvmFinalize, + Function as SvmFunctionParam, Inverse as _, Network as _, Pow as _, @@ -49,16 +52,20 @@ use snarkvm::prelude::{ ToBits, }; -use indexmap::IndexSet; +use indexmap::{IndexMap, IndexSet}; use rand::Rng as _; use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng}; use std::{cmp::Ordering, collections::HashMap, fmt, mem, str::FromStr as _}; +pub type Closure = SvmClosure; +pub type Finalize = SvmFinalize; +pub type SvmFunction = SvmFunctionParam; + /// Names associated to values in a function being executed. #[derive(Clone, Debug)] -struct FunctionContext { +pub struct FunctionContext { program: Symbol, - caller: SvmAddress, + pub caller: SvmAddress, names: HashMap, accumulated_futures: Future, is_async: bool, @@ -117,7 +124,7 @@ impl ContextStack { self.last_mut().unwrap().names.insert(symbol, value); } - fn add_future(&mut self, future: Future) { + pub fn add_future(&mut self, future: Future) { assert!(self.current_len > 0); self.contexts[self.current_len - 1].accumulated_futures.0.extend(future.0); } @@ -128,11 +135,11 @@ impl ContextStack { self.last().unwrap().is_async } - fn current_program(&self) -> Option { + pub fn current_program(&self) -> Option { self.last().map(|c| c.program) } - fn last(&self) -> Option<&FunctionContext> { + pub fn last(&self) -> Option<&FunctionContext> { self.len().checked_sub(1).and_then(|i| self.contexts.get(i)) } @@ -141,8 +148,15 @@ impl ContextStack { } } -/// A Leo construct to be evauated. #[derive(Copy, Clone, Debug)] +pub enum AleoContext<'a> { + Closure(&'a Closure), + Function(&'a SvmFunction), + Finalize(&'a Finalize), +} + +/// A Leo construct to be evauated. +#[derive(Clone, Debug)] pub enum Element<'a> { /// A Leo statement. Statement(&'a Statement), @@ -163,6 +177,12 @@ pub enum Element<'a> { function_body: bool, }, + AleoExecution { + context: AleoContext<'a>, + registers: IndexMap, + instruction_index: usize, + }, + DelayedCall(GlobalId), } @@ -173,7 +193,7 @@ impl Element<'_> { Statement(statement) => statement.span(), Expression(expression) => expression.span(), Block { block, .. } => block.span(), - DelayedCall(..) => Default::default(), + AleoExecution { .. } | DelayedCall(..) => Default::default(), } } } @@ -201,6 +221,13 @@ impl fmt::Display for GlobalId { } } +#[derive(Clone, Debug)] +pub enum FunctionVariant<'a> { + Leo(&'a Function), + AleoClosure(&'a Closure), + AleoFunction(&'a SvmFunction), +} + /// Tracks the current execution state - a cursor into the running program. #[derive(Clone, Debug)] pub struct Cursor<'a> { @@ -213,7 +240,7 @@ pub struct Cursor<'a> { pub values: Vec, /// All functions (or transitions or inlines) in any program being interpreted. - pub functions: HashMap, + pub functions: HashMap>, /// Consts are stored here. pub globals: HashMap, @@ -227,13 +254,13 @@ pub struct Cursor<'a> { pub contexts: ContextStack, - signer: SvmAddress, + pub signer: SvmAddress, rng: ChaCha20Rng, - block_height: u32, + pub block_height: u32, - really_async: bool, + pub really_async: bool, } impl<'a> Cursor<'a> { @@ -255,6 +282,23 @@ impl<'a> Cursor<'a> { } } + pub fn increment_step(&mut self) { + let Some(Frame { step, .. }) = self.frames.last_mut() else { + panic!("frame expected"); + }; + *step += 1; + } + + fn new_caller(&self) -> SvmAddress { + if let Some(function_context) = self.contexts.last() { + let program_id = ProgramID::::from_str(&format!("{}.aleo", function_context.program)) + .expect("should be able to create ProgramID"); + program_id.to_address().expect("should be able to convert to address") + } else { + self.signer + } + } + fn pop_value(&mut self) -> Result { match self.values.pop() { Some(v) => Ok(v), @@ -292,7 +336,7 @@ impl<'a> Cursor<'a> { self.mappings.get_mut(&GlobalId { program, name }) } - fn lookup_function(&self, program: Symbol, name: Symbol) -> Option<&'a Function> { + fn lookup_function(&self, program: Symbol, name: Symbol) -> Option> { self.functions.get(&GlobalId { program, name }).cloned() } @@ -652,1056 +696,8 @@ impl<'a> Cursor<'a> { let span = function.span(); - macro_rules! apply { - ($func: expr, $value: ident, $to: ident) => {{ - let v = self.pop_value()?; - let bits = v.$to(); - Value::$value($func(&bits).expect_tc(span)?) - }}; - } - - macro_rules! apply_cast { - ($func: expr, $value: ident, $to: ident) => {{ - let v = self.pop_value()?; - let bits = v.$to(); - let group = $func(&bits).expect_tc(span)?; - let x = group.to_x_coordinate(); - Value::$value(x.cast_lossy()) - }}; - } - - macro_rules! apply_cast_int { - ($func: expr, $value: ident, $int_ty: ident, $to: ident) => {{ - let v = self.pop_value()?; - let bits = v.$to(); - let group = $func(&bits).expect_tc(span)?; - let x = group.to_x_coordinate(); - let bits = x.to_bits_le(); - let mut result: $int_ty = 0; - for bit in 0..std::cmp::min($int_ty::BITS as usize, bits.len()) { - let setbit = (if bits[bit] { 1 } else { 0 }) << bit; - result |= setbit; - } - Value::$value(result) - }}; - } + let value = self.evaluate_core_function(core_function, &function.arguments, span)?; - macro_rules! apply_cast2 { - ($func: expr, $value: ident) => {{ - let Value::Scalar(randomizer) = self.pop_value()? else { - tc_fail!(); - }; - let v = self.pop_value()?; - let bits = v.to_bits_le(); - let group = $func(&bits, &randomizer).expect_tc(span)?; - let x = group.to_x_coordinate(); - Value::$value(x.cast_lossy()) - }}; - } - - let value = match core_function { - CoreFunction::BHP256CommitToAddress => { - apply_cast2!(TestnetV0::commit_to_group_bhp256, Address) - } - CoreFunction::BHP256CommitToField => { - apply_cast2!(TestnetV0::commit_to_group_bhp256, Field) - } - CoreFunction::BHP256CommitToGroup => { - apply_cast2!(TestnetV0::commit_to_group_bhp256, Group) - } - CoreFunction::BHP256HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_bhp256, Address, to_bits_le) - } - CoreFunction::BHP256HashToField => apply!(TestnetV0::hash_bhp256, Field, to_bits_le), - CoreFunction::BHP256HashToGroup => apply!(TestnetV0::hash_to_group_bhp256, Group, to_bits_le), - CoreFunction::BHP256HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, I8, i8, to_bits_le) - } - CoreFunction::BHP256HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, I16, i16, to_bits_le) - } - CoreFunction::BHP256HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, I32, i32, to_bits_le) - } - CoreFunction::BHP256HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, I64, i64, to_bits_le) - } - CoreFunction::BHP256HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, I128, i128, to_bits_le) - } - CoreFunction::BHP256HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, U8, u8, to_bits_le) - } - CoreFunction::BHP256HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, U16, u16, to_bits_le) - } - CoreFunction::BHP256HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, U32, u32, to_bits_le) - } - CoreFunction::BHP256HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, U64, u64, to_bits_le) - } - CoreFunction::BHP256HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp256, U128, u128, to_bits_le) - } - CoreFunction::BHP256HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_bhp256, Scalar, to_bits_le) - } - CoreFunction::BHP512CommitToAddress => { - apply_cast2!(TestnetV0::commit_to_group_bhp512, Address) - } - CoreFunction::BHP512CommitToField => { - apply_cast2!(TestnetV0::commit_to_group_bhp512, Field) - } - CoreFunction::BHP512CommitToGroup => { - apply_cast2!(TestnetV0::commit_to_group_bhp512, Group) - } - CoreFunction::BHP512HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_bhp512, Address, to_bits_le) - } - CoreFunction::BHP512HashToField => apply!(TestnetV0::hash_bhp512, Field, to_bits_le), - CoreFunction::BHP512HashToGroup => apply!(TestnetV0::hash_to_group_bhp512, Group, to_bits_le), - CoreFunction::BHP512HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, I8, i8, to_bits_le) - } - CoreFunction::BHP512HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, I16, i16, to_bits_le) - } - CoreFunction::BHP512HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, I32, i32, to_bits_le) - } - CoreFunction::BHP512HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, I64, i64, to_bits_le) - } - CoreFunction::BHP512HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, I128, i128, to_bits_le) - } - CoreFunction::BHP512HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, U8, u8, to_bits_le) - } - CoreFunction::BHP512HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, U16, u16, to_bits_le) - } - CoreFunction::BHP512HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, U32, u32, to_bits_le) - } - CoreFunction::BHP512HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, U64, u64, to_bits_le) - } - CoreFunction::BHP512HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp512, U128, u128, to_bits_le) - } - CoreFunction::BHP512HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_bhp512, Scalar, to_bits_le) - } - CoreFunction::BHP768CommitToAddress => { - apply_cast2!(TestnetV0::commit_to_group_bhp768, Address) - } - CoreFunction::BHP768CommitToField => { - apply_cast2!(TestnetV0::commit_to_group_bhp768, Field) - } - CoreFunction::BHP768CommitToGroup => { - apply_cast2!(TestnetV0::commit_to_group_bhp768, Group) - } - CoreFunction::BHP768HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_bhp768, Address, to_bits_le) - } - CoreFunction::BHP768HashToField => apply!(TestnetV0::hash_bhp768, Field, to_bits_le), - CoreFunction::BHP768HashToGroup => apply!(TestnetV0::hash_to_group_bhp768, Group, to_bits_le), - CoreFunction::BHP768HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, I8, i8, to_bits_le) - } - CoreFunction::BHP768HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, I16, i16, to_bits_le) - } - CoreFunction::BHP768HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, I32, i32, to_bits_le) - } - CoreFunction::BHP768HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, I64, i64, to_bits_le) - } - CoreFunction::BHP768HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, I128, i128, to_bits_le) - } - CoreFunction::BHP768HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, U8, u8, to_bits_le) - } - CoreFunction::BHP768HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, U16, u16, to_bits_le) - } - CoreFunction::BHP768HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, U32, u32, to_bits_le) - } - CoreFunction::BHP768HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, U64, u64, to_bits_le) - } - CoreFunction::BHP768HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp768, U128, u128, to_bits_le) - } - CoreFunction::BHP768HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_bhp768, Scalar, to_bits_le) - } - CoreFunction::BHP1024CommitToAddress => { - apply_cast2!(TestnetV0::commit_to_group_bhp1024, Address) - } - CoreFunction::BHP1024CommitToField => { - apply_cast2!(TestnetV0::commit_to_group_bhp1024, Field) - } - CoreFunction::BHP1024CommitToGroup => { - apply_cast2!(TestnetV0::commit_to_group_bhp1024, Group) - } - CoreFunction::BHP1024HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_bhp1024, Address, to_bits_le) - } - CoreFunction::BHP1024HashToField => apply!(TestnetV0::hash_bhp1024, Field, to_bits_le), - CoreFunction::BHP1024HashToGroup => apply!(TestnetV0::hash_to_group_bhp1024, Group, to_bits_le), - CoreFunction::BHP1024HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I8, i8, to_bits_le) - } - CoreFunction::BHP1024HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I16, i16, to_bits_le) - } - CoreFunction::BHP1024HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I32, i32, to_bits_le) - } - CoreFunction::BHP1024HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I64, i64, to_bits_le) - } - CoreFunction::BHP1024HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I128, i128, to_bits_le) - } - CoreFunction::BHP1024HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U8, u8, to_bits_le) - } - CoreFunction::BHP1024HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U16, u16, to_bits_le) - } - CoreFunction::BHP1024HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U32, u32, to_bits_le) - } - CoreFunction::BHP1024HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U64, u64, to_bits_le) - } - CoreFunction::BHP1024HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U128, u128, to_bits_le) - } - CoreFunction::BHP1024HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_bhp1024, Scalar, to_bits_le) - } - CoreFunction::ChaChaRandAddress => Value::Address(self.rng.gen()), - CoreFunction::ChaChaRandBool => Value::Bool(self.rng.gen()), - CoreFunction::ChaChaRandField => Value::Field(self.rng.gen()), - CoreFunction::ChaChaRandGroup => Value::Group(self.rng.gen()), - CoreFunction::ChaChaRandI8 => Value::I8(self.rng.gen()), - CoreFunction::ChaChaRandI16 => Value::I16(self.rng.gen()), - CoreFunction::ChaChaRandI32 => Value::I32(self.rng.gen()), - CoreFunction::ChaChaRandI64 => Value::I64(self.rng.gen()), - CoreFunction::ChaChaRandI128 => Value::I128(self.rng.gen()), - CoreFunction::ChaChaRandU8 => Value::U8(self.rng.gen()), - CoreFunction::ChaChaRandU16 => Value::U16(self.rng.gen()), - CoreFunction::ChaChaRandU32 => Value::U32(self.rng.gen()), - CoreFunction::ChaChaRandU64 => Value::U64(self.rng.gen()), - CoreFunction::ChaChaRandU128 => Value::U128(self.rng.gen()), - CoreFunction::ChaChaRandScalar => Value::Scalar(self.rng.gen()), - CoreFunction::Keccak256HashToAddress => apply_cast!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - Address, - to_bits_le - ), - CoreFunction::Keccak256HashToField => apply_cast!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - Field, - to_bits_le - ), - CoreFunction::Keccak256HashToGroup => { - apply!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - Group, - to_bits_le - ) - } - CoreFunction::Keccak256HashToI8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - I8, - i8, - to_bits_le - ), - CoreFunction::Keccak256HashToI16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - I16, - i16, - to_bits_le - ), - - CoreFunction::Keccak256HashToI32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - I32, - i32, - to_bits_le - ), - CoreFunction::Keccak256HashToI64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - I64, - i64, - to_bits_le - ), - CoreFunction::Keccak256HashToI128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - I128, - i128, - to_bits_le - ), - CoreFunction::Keccak256HashToU8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - U8, - u8, - to_bits_le - ), - CoreFunction::Keccak256HashToU16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - U16, - u16, - to_bits_le - ), - CoreFunction::Keccak256HashToU32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - U32, - u32, - to_bits_le - ), - CoreFunction::Keccak256HashToU64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - U64, - u64, - to_bits_le - ), - CoreFunction::Keccak256HashToU128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - U128, - u128, - to_bits_le - ), - CoreFunction::Keccak256HashToScalar => apply_cast!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), - Scalar, - to_bits_le - ), - CoreFunction::Keccak384HashToAddress => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - Address, - to_bits_le - ), - CoreFunction::Keccak384HashToField => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - Field, - to_bits_le - ), - CoreFunction::Keccak384HashToGroup => { - apply!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - Group, - to_bits_le - ) - } - CoreFunction::Keccak384HashToI8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - I8, - i8, - to_bits_le - ), - CoreFunction::Keccak384HashToI16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - I16, - i16, - to_bits_le - ), - CoreFunction::Keccak384HashToI32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - I32, - i32, - to_bits_le - ), - CoreFunction::Keccak384HashToI64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - I64, - i64, - to_bits_le - ), - CoreFunction::Keccak384HashToI128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - I128, - i128, - to_bits_le - ), - CoreFunction::Keccak384HashToU8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - U8, - u8, - to_bits_le - ), - CoreFunction::Keccak384HashToU16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - U16, - u16, - to_bits_le - ), - CoreFunction::Keccak384HashToU32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - U32, - u32, - to_bits_le - ), - CoreFunction::Keccak384HashToU64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - U64, - u64, - to_bits_le - ), - CoreFunction::Keccak384HashToU128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - U128, - u128, - to_bits_le - ), - CoreFunction::Keccak384HashToScalar => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), - Scalar, - to_bits_le - ), - CoreFunction::Keccak512HashToAddress => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - Address, - to_bits_le - ), - CoreFunction::Keccak512HashToField => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - Field, - to_bits_le - ), - CoreFunction::Keccak512HashToGroup => { - apply!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - Group, - to_bits_le - ) - } - CoreFunction::Keccak512HashToI8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - I8, - i8, - to_bits_le - ), - CoreFunction::Keccak512HashToI16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - I16, - i16, - to_bits_le - ), - CoreFunction::Keccak512HashToI32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - I32, - i32, - to_bits_le - ), - CoreFunction::Keccak512HashToI64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - I64, - i64, - to_bits_le - ), - CoreFunction::Keccak512HashToI128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - I128, - i128, - to_bits_le - ), - CoreFunction::Keccak512HashToU8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - U8, - u8, - to_bits_le - ), - CoreFunction::Keccak512HashToU16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - U16, - u16, - to_bits_le - ), - CoreFunction::Keccak512HashToU32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - U32, - u32, - to_bits_le - ), - CoreFunction::Keccak512HashToU64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - U64, - u64, - to_bits_le - ), - CoreFunction::Keccak512HashToU128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - U128, - u128, - to_bits_le - ), - CoreFunction::Keccak512HashToScalar => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), - Scalar, - to_bits_le - ), - CoreFunction::Pedersen64CommitToAddress => { - apply_cast2!(TestnetV0::commit_to_group_ped64, Address) - } - CoreFunction::Pedersen64CommitToField => { - apply_cast2!(TestnetV0::commit_to_group_ped64, Field) - } - CoreFunction::Pedersen64CommitToGroup => { - apply_cast2!(TestnetV0::commit_to_group_ped64, Group) - } - CoreFunction::Pedersen64HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_ped64, Address, to_bits_le) - } - CoreFunction::Pedersen64HashToField => apply!(TestnetV0::hash_ped64, Field, to_bits_le), - CoreFunction::Pedersen64HashToGroup => apply!(TestnetV0::hash_to_group_ped64, Group, to_bits_le), - CoreFunction::Pedersen64HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, I8, i8, to_bits_le) - } - CoreFunction::Pedersen64HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, I16, i16, to_bits_le) - } - CoreFunction::Pedersen64HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, I32, i32, to_bits_le) - } - CoreFunction::Pedersen64HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, I64, i64, to_bits_le) - } - CoreFunction::Pedersen64HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, I128, i128, to_bits_le) - } - CoreFunction::Pedersen64HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, U8, u8, to_bits_le) - } - CoreFunction::Pedersen64HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, U16, u16, to_bits_le) - } - CoreFunction::Pedersen64HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, U32, u32, to_bits_le) - } - CoreFunction::Pedersen64HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, U64, u64, to_bits_le) - } - CoreFunction::Pedersen64HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, U128, u128, to_bits_le) - } - CoreFunction::Pedersen64HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_ped64, Scalar, to_bits_le) - } - CoreFunction::Pedersen128HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_ped128, Address, to_bits_le) - } - CoreFunction::Pedersen128HashToField => { - apply_cast!(TestnetV0::hash_to_group_ped128, Field, to_bits_le) - } - CoreFunction::Pedersen128HashToGroup => { - apply_cast!(TestnetV0::hash_to_group_ped128, Group, to_bits_le) - } - CoreFunction::Pedersen128HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_ped128, I8, i8, to_bits_le) - } - CoreFunction::Pedersen128HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, I16, i16, to_bits_le) - } - CoreFunction::Pedersen128HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_ped128, I32, i32, to_bits_le) - } - CoreFunction::Pedersen128HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, I64, i64, to_bits_le) - } - CoreFunction::Pedersen128HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_ped128, I128, i128, to_bits_le) - } - CoreFunction::Pedersen128HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_ped128, U8, u8, to_bits_le) - } - CoreFunction::Pedersen128HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, U16, u16, to_bits_le) - } - CoreFunction::Pedersen128HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_ped128, U32, u32, to_bits_le) - } - CoreFunction::Pedersen128HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_ped64, U64, u64, to_bits_le) - } - CoreFunction::Pedersen128HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_ped128, U128, u128, to_bits_le) - } - CoreFunction::Pedersen128HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_ped128, Scalar, to_bits_le) - } - CoreFunction::Pedersen128CommitToAddress => { - apply_cast2!(TestnetV0::commit_to_group_ped128, Address) - } - CoreFunction::Pedersen128CommitToField => { - apply_cast2!(TestnetV0::commit_to_group_ped128, Field) - } - CoreFunction::Pedersen128CommitToGroup => { - apply_cast2!(TestnetV0::commit_to_group_ped128, Group) - } - CoreFunction::Poseidon2HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_psd2, Address, to_fields) - } - CoreFunction::Poseidon2HashToField => { - apply_cast!(TestnetV0::hash_to_group_psd2, Field, to_fields) - } - CoreFunction::Poseidon2HashToGroup => { - apply_cast!(TestnetV0::hash_to_group_psd2, Group, to_fields) - } - CoreFunction::Poseidon2HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, I8, i8, to_fields) - } - CoreFunction::Poseidon2HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, I16, i16, to_fields) - } - CoreFunction::Poseidon2HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, I32, i32, to_fields) - } - CoreFunction::Poseidon2HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, I64, i64, to_fields) - } - CoreFunction::Poseidon2HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, I128, i128, to_fields) - } - CoreFunction::Poseidon2HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, U8, u8, to_fields) - } - CoreFunction::Poseidon2HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, U16, u16, to_fields) - } - CoreFunction::Poseidon2HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, U32, u32, to_fields) - } - CoreFunction::Poseidon2HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, U64, u64, to_fields) - } - CoreFunction::Poseidon2HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_psd2, U128, u128, to_fields) - } - CoreFunction::Poseidon2HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_psd4, Scalar, to_fields) - } - CoreFunction::Poseidon4HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_psd4, Address, to_fields) - } - CoreFunction::Poseidon4HashToField => { - apply_cast!(TestnetV0::hash_to_group_psd4, Field, to_fields) - } - CoreFunction::Poseidon4HashToGroup => { - apply_cast!(TestnetV0::hash_to_group_psd4, Group, to_fields) - } - CoreFunction::Poseidon4HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, I8, i8, to_fields) - } - CoreFunction::Poseidon4HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, I16, i16, to_fields) - } - CoreFunction::Poseidon4HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, I32, i32, to_fields) - } - CoreFunction::Poseidon4HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, I64, i64, to_fields) - } - CoreFunction::Poseidon4HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, I128, i128, to_fields) - } - CoreFunction::Poseidon4HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, U8, u8, to_fields) - } - CoreFunction::Poseidon4HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, U16, u16, to_fields) - } - CoreFunction::Poseidon4HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, U32, u32, to_fields) - } - CoreFunction::Poseidon4HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, U64, u64, to_fields) - } - CoreFunction::Poseidon4HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_psd4, U128, u128, to_fields) - } - CoreFunction::Poseidon4HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_psd4, Scalar, to_fields) - } - CoreFunction::Poseidon8HashToAddress => { - apply_cast!(TestnetV0::hash_to_group_psd8, Address, to_fields) - } - CoreFunction::Poseidon8HashToField => { - apply_cast!(TestnetV0::hash_to_group_psd8, Field, to_fields) - } - CoreFunction::Poseidon8HashToGroup => { - apply_cast!(TestnetV0::hash_to_group_psd8, Group, to_fields) - } - CoreFunction::Poseidon8HashToI8 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, I8, i8, to_fields) - } - CoreFunction::Poseidon8HashToI16 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, I16, i16, to_fields) - } - CoreFunction::Poseidon8HashToI32 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, I32, i32, to_fields) - } - CoreFunction::Poseidon8HashToI64 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, I64, i64, to_fields) - } - CoreFunction::Poseidon8HashToI128 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, I128, i128, to_fields) - } - CoreFunction::Poseidon8HashToU8 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, U8, u8, to_fields) - } - CoreFunction::Poseidon8HashToU16 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, U16, u16, to_fields) - } - CoreFunction::Poseidon8HashToU32 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, U32, u32, to_fields) - } - CoreFunction::Poseidon8HashToU64 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, U64, u64, to_fields) - } - CoreFunction::Poseidon8HashToU128 => { - apply_cast_int!(TestnetV0::hash_to_group_psd8, U128, u128, to_fields) - } - CoreFunction::Poseidon8HashToScalar => { - apply_cast!(TestnetV0::hash_to_group_psd8, Scalar, to_fields) - } - CoreFunction::SHA3_256HashToAddress => apply_cast!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - Address, - to_bits_le - ), - CoreFunction::SHA3_256HashToField => apply_cast!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - Field, - to_bits_le - ), - CoreFunction::SHA3_256HashToGroup => apply_cast!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - Group, - to_bits_le - ), - CoreFunction::SHA3_256HashToI8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - I8, - i8, - to_bits_le - ), - CoreFunction::SHA3_256HashToI16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - I16, - i16, - to_bits_le - ), - CoreFunction::SHA3_256HashToI32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - I32, - i32, - to_bits_le - ), - CoreFunction::SHA3_256HashToI64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - I64, - i64, - to_bits_le - ), - CoreFunction::SHA3_256HashToI128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - I128, - i128, - to_bits_le - ), - CoreFunction::SHA3_256HashToU8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - U8, - u8, - to_bits_le - ), - CoreFunction::SHA3_256HashToU16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - U16, - u16, - to_bits_le - ), - CoreFunction::SHA3_256HashToU32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - U32, - u32, - to_bits_le - ), - CoreFunction::SHA3_256HashToU64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - U64, - u64, - to_bits_le - ), - CoreFunction::SHA3_256HashToU128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - U128, - u128, - to_bits_le - ), - CoreFunction::SHA3_256HashToScalar => apply_cast!( - |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), - Scalar, - to_bits_le - ), - CoreFunction::SHA3_384HashToAddress => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - Address, - to_bits_le - ), - CoreFunction::SHA3_384HashToField => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - Field, - to_bits_le - ), - CoreFunction::SHA3_384HashToGroup => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - Group, - to_bits_le - ), - CoreFunction::SHA3_384HashToI8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - I8, - i8, - to_bits_le - ), - CoreFunction::SHA3_384HashToI16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - I16, - i16, - to_bits_le - ), - CoreFunction::SHA3_384HashToI32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - I32, - i32, - to_bits_le - ), - CoreFunction::SHA3_384HashToI64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - I64, - i64, - to_bits_le - ), - CoreFunction::SHA3_384HashToI128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - I128, - i128, - to_bits_le - ), - CoreFunction::SHA3_384HashToU8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - U8, - u8, - to_bits_le - ), - CoreFunction::SHA3_384HashToU16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - U16, - u16, - to_bits_le - ), - CoreFunction::SHA3_384HashToU32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - U32, - u32, - to_bits_le - ), - CoreFunction::SHA3_384HashToU64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - U64, - u64, - to_bits_le - ), - CoreFunction::SHA3_384HashToU128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - U128, - u128, - to_bits_le - ), - CoreFunction::SHA3_384HashToScalar => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), - Scalar, - to_bits_le - ), - CoreFunction::SHA3_512HashToAddress => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - Address, - to_bits_le - ), - CoreFunction::SHA3_512HashToField => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - Field, - to_bits_le - ), - CoreFunction::SHA3_512HashToGroup => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - Group, - to_bits_le - ), - CoreFunction::SHA3_512HashToI8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - I8, - i8, - to_bits_le - ), - CoreFunction::SHA3_512HashToI16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - I16, - i16, - to_bits_le - ), - CoreFunction::SHA3_512HashToI32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - I32, - i32, - to_bits_le - ), - CoreFunction::SHA3_512HashToI64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - I64, - i64, - to_bits_le - ), - CoreFunction::SHA3_512HashToI128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - I128, - i128, - to_bits_le - ), - CoreFunction::SHA3_512HashToU8 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - U8, - u8, - to_bits_le - ), - CoreFunction::SHA3_512HashToU16 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - U16, - u16, - to_bits_le - ), - CoreFunction::SHA3_512HashToU32 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - U32, - u32, - to_bits_le - ), - CoreFunction::SHA3_512HashToU64 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - U64, - u64, - to_bits_le - ), - CoreFunction::SHA3_512HashToU128 => apply_cast_int!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - U128, - u128, - to_bits_le - ), - CoreFunction::SHA3_512HashToScalar => apply_cast!( - |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), - Scalar, - to_bits_le - ), - CoreFunction::MappingGet => { - let key = self.values.pop().expect_tc(span)?; - let (program, name) = match &function.arguments[0] { - Expression::Identifier(id) => (None, id.name), - Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), - _ => tc_fail!(), - }; - match self.lookup_mapping(program, name).and_then(|mapping| mapping.get(&key)) { - Some(v) => v.clone(), - None => halt!(function.span(), "map lookup failure"), - } - } - CoreFunction::MappingGetOrUse => { - let use_value = self.values.pop().expect_tc(span)?; - let key = self.values.pop().expect_tc(span)?; - let (program, name) = match &function.arguments[0] { - Expression::Identifier(id) => (None, id.name), - Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), - _ => tc_fail!(), - }; - match self.lookup_mapping(program, name).and_then(|mapping| mapping.get(&key)) { - Some(v) => v.clone(), - None => use_value, - } - } - CoreFunction::MappingSet => { - let value = self.pop_value()?; - let key = self.pop_value()?; - let (program, name) = match &function.arguments[0] { - Expression::Identifier(id) => (None, id.name), - Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), - _ => tc_fail!(), - }; - if let Some(mapping) = self.lookup_mapping_mut(program, name) { - mapping.insert(key, value); - } else { - tc_fail!(); - } - Value::Unit - } - CoreFunction::MappingRemove => { - let key = self.pop_value()?; - let (program, name) = match &function.arguments[0] { - Expression::Identifier(id) => (None, id.name), - Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), - _ => tc_fail!(), - }; - if let Some(mapping) = self.lookup_mapping_mut(program, name) { - mapping.remove(&key); - } else { - tc_fail!(); - } - Value::Unit - } - CoreFunction::MappingContains => { - let key = self.pop_value()?; - let (program, name) = match &function.arguments[0] { - Expression::Identifier(id) => (None, id.name), - Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), - _ => tc_fail!(), - }; - if let Some(mapping) = self.lookup_mapping_mut(program, name) { - Value::Bool(mapping.contains_key(&key)) - } else { - tc_fail!(); - } - } - CoreFunction::GroupToXCoordinate => { - let Value::Group(g) = self.pop_value()? else { - tc_fail!(); - }; - Value::Field(g.to_x_coordinate()) - } - CoreFunction::GroupToYCoordinate => { - let Value::Group(g) = self.pop_value()? else { - tc_fail!(); - }; - Value::Field(g.to_y_coordinate()) - } - CoreFunction::SignatureVerify => todo!(), - CoreFunction::FutureAwait => { - let Value::Future(future) = self.pop_value()? else { - tc_fail!(); - }; - self.contexts.add_future(future); - Value::Unit - } - }; Some(value) } Expression::Array(array) if step == 0 => { @@ -1739,37 +735,16 @@ impl<'a> Cursor<'a> { Expression::Locator(locator) => (locator.program.name.name, locator.name), _ => tc_fail!(), }; - let function = self.lookup_function(program, name).expect_tc(call.span())?; - let values_iter = self.values.drain(len - call.arguments.len()..); - if self.really_async && function.variant == Variant::AsyncFunction { - // Don't actually run the call now. - let async_ex = - AsyncExecution { function: GlobalId { name, program }, arguments: values_iter.collect() }; - self.values.push(Value::Future(Future(vec![async_ex]))); - } else { - let is_async = function.variant == Variant::AsyncFunction; - let caller = if matches!(function.variant, Variant::Transition | Variant::AsyncTransition) { - if let Some(function_context) = self.contexts.last() { - let program_id = ProgramID::::from_str(&format!("{}", function_context.program)) - .expect("should be able to create ProgramID"); - program_id.to_address().expect("should be able to convert to address") - } else { - self.signer - } - } else { - self.signer - }; - self.contexts.push(program, caller, is_async); - let param_names = function.input.iter().map(|input| input.identifier.name); - for (name, value) in param_names.zip(values_iter) { - self.contexts.set(name, value); - } - self.frames.push(Frame { - step: 0, - element: Element::Block { block: &function.block, function_body: true }, - user_initiated: false, - }); - } + // It's a bit cheesy to collect the arguments into a Vec first, but it's the easiest way + // to handle lifetimes here. + let arguments: Vec = self.values.drain(len - call.arguments.len()..).collect(); + self.do_call( + program, + name, + arguments.into_iter(), + false, // finalize + call.span(), + )?; None } Expression::Call(_call) if step == 2 => Some(self.pop_value()?), @@ -1922,27 +897,58 @@ impl<'a> Cursor<'a> { } Ok(StepResult { finished, value }) } + Element::AleoExecution { .. } => { + self.step_aleo()?; + Ok(StepResult { finished: true, value: None }) + } Element::DelayedCall(gid) if *step == 0 => { - let function = self.lookup_function(gid.program, gid.name).expect("function should exist"); - assert!(function.variant == Variant::AsyncFunction); - let len = self.values.len(); - let values_iter = self.values.drain(len - function.input.len()..); - self.contexts.push( - gid.program, - self.signer, - true, // is_async - ); - let param_names = function.input.iter().map(|input| input.identifier.name); - for (name, value) in param_names.zip(values_iter) { - self.contexts.set(name, value); + match self.lookup_function(gid.program, gid.name).expect("function should exist") { + FunctionVariant::Leo(function) => { + assert!(function.variant == Variant::AsyncFunction); + let len = self.values.len(); + let values_iter = self.values.drain(len - function.input.len()..); + self.contexts.push( + gid.program, + self.signer, + true, // is_async + ); + let param_names = function.input.iter().map(|input| input.identifier.name); + for (name, value) in param_names.zip(values_iter) { + self.contexts.set(name, value); + } + self.frames.last_mut().unwrap().step = 1; + self.frames.push(Frame { + step: 0, + element: Element::Block { block: &function.block, function_body: true }, + user_initiated: false, + }); + Ok(StepResult { finished: false, value: None }) + } + FunctionVariant::AleoFunction(function) => { + let Some(finalize_f) = function.finalize_logic() else { + panic!("must have finalize logic for a delayed call"); + }; + let len = self.values.len(); + let values_iter = self.values.drain(len - finalize_f.inputs().len()..); + self.contexts.push( + gid.program, + self.signer, + true, // is_async + ); + self.frames.last_mut().unwrap().step = 1; + self.frames.push(Frame { + step: 0, + element: Element::AleoExecution { + context: AleoContext::Finalize(finalize_f), + registers: values_iter.enumerate().map(|(i, v)| (i as u64, v)).collect(), + instruction_index: 0, + }, + user_initiated: false, + }); + Ok(StepResult { finished: false, value: None }) + } + FunctionVariant::AleoClosure(..) => panic!("A call to a closure can't be delayed"), } - self.frames.last_mut().unwrap().step = 1; - self.frames.push(Frame { - step: 0, - element: Element::Block { block: &function.block, function_body: true }, - user_initiated: false, - }); - Ok(StepResult { finished: false, value: None }) } Element::DelayedCall(_gid) => { assert_eq!(*step, 1); @@ -1958,6 +964,1144 @@ impl<'a> Cursor<'a> { } } } + + pub fn do_call( + &mut self, + function_program: Symbol, + function_name: Symbol, + arguments: impl Iterator, + finalize: bool, + span: Span, + ) -> Result<()> { + let Some(function_variant) = self.lookup_function(function_program, function_name) else { + halt!(span, "unknown function {function_program}.aleo/{function_name}"); + }; + match function_variant { + FunctionVariant::Leo(function) => { + let caller = if matches!(function.variant, Variant::Transition | Variant::AsyncTransition) { + self.new_caller() + } else { + self.signer + }; + if self.really_async && function.variant == Variant::AsyncFunction { + // Don't actually run the call now. + let async_ex = AsyncExecution { + function: GlobalId { name: function_name, program: function_program }, + arguments: arguments.collect(), + }; + self.values.push(Value::Future(Future(vec![async_ex]))); + } else { + let is_async = function.variant == Variant::AsyncFunction; + self.contexts.push(function_program, caller, is_async); + let param_names = function.input.iter().map(|input| input.identifier.name); + for (name, value) in param_names.zip(arguments) { + self.contexts.set(name, value); + } + self.frames.push(Frame { + step: 0, + element: Element::Block { block: &function.block, function_body: true }, + user_initiated: false, + }); + } + } + FunctionVariant::AleoClosure(closure) => { + self.contexts.push(function_program, self.signer, false); + let context = AleoContext::Closure(closure); + self.frames.push(Frame { + step: 0, + element: Element::AleoExecution { + context, + registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(), + instruction_index: 0, + }, + user_initiated: false, + }); + } + FunctionVariant::AleoFunction(function) => { + let caller = self.new_caller(); + self.contexts.push(function_program, caller, false); + let context = if finalize { + let Some(finalize_f) = function.finalize_logic() else { + panic!("finalize call with no finalize logic"); + }; + AleoContext::Finalize(finalize_f) + } else { + AleoContext::Function(function) + }; + self.frames.push(Frame { + step: 0, + element: Element::AleoExecution { + context, + registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(), + instruction_index: 0, + }, + user_initiated: false, + }); + } + } + + Ok(()) + } + + pub fn evaluate_core_function( + &mut self, + core_function: CoreFunction, + arguments: &[Expression], + span: Span, + ) -> Result { + macro_rules! apply { + ($func: expr, $value: ident, $to: ident) => {{ + let v = self.pop_value()?; + let bits = v.$to(); + Value::$value($func(&bits).expect_tc(span)?) + }}; + } + + macro_rules! apply_cast { + ($func: expr, $value: ident, $to: ident) => {{ + let v = self.pop_value()?; + let bits = v.$to(); + let group = $func(&bits).expect_tc(span)?; + let x = group.to_x_coordinate(); + Value::$value(x.cast_lossy()) + }}; + } + + macro_rules! apply_cast_int { + ($func: expr, $value: ident, $int_ty: ident, $to: ident) => {{ + let v = self.pop_value()?; + let bits = v.$to(); + let group = $func(&bits).expect_tc(span)?; + let x = group.to_x_coordinate(); + let bits = x.to_bits_le(); + let mut result: $int_ty = 0; + for bit in 0..std::cmp::min($int_ty::BITS as usize, bits.len()) { + let setbit = (if bits[bit] { 1 } else { 0 }) << bit; + result |= setbit; + } + Value::$value(result) + }}; + } + + macro_rules! apply_cast2 { + ($func: expr, $value: ident) => {{ + let Value::Scalar(randomizer) = self.pop_value()? else { + tc_fail!(); + }; + let v = self.pop_value()?; + let bits = v.to_bits_le(); + let group = $func(&bits, &randomizer).expect_tc(span)?; + let x = group.to_x_coordinate(); + Value::$value(x.cast_lossy()) + }}; + } + + let value = match core_function { + CoreFunction::BHP256CommitToAddress => { + apply_cast2!(TestnetV0::commit_to_group_bhp256, Address) + } + CoreFunction::BHP256CommitToField => { + apply_cast2!(TestnetV0::commit_to_group_bhp256, Field) + } + CoreFunction::BHP256CommitToGroup => { + apply_cast2!(TestnetV0::commit_to_group_bhp256, Group) + } + CoreFunction::BHP256HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_bhp256, Address, to_bits_le) + } + CoreFunction::BHP256HashToField => apply!(TestnetV0::hash_bhp256, Field, to_bits_le), + CoreFunction::BHP256HashToGroup => apply!(TestnetV0::hash_to_group_bhp256, Group, to_bits_le), + CoreFunction::BHP256HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, I8, i8, to_bits_le) + } + CoreFunction::BHP256HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, I16, i16, to_bits_le) + } + CoreFunction::BHP256HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, I32, i32, to_bits_le) + } + CoreFunction::BHP256HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, I64, i64, to_bits_le) + } + CoreFunction::BHP256HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, I128, i128, to_bits_le) + } + CoreFunction::BHP256HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, U8, u8, to_bits_le) + } + CoreFunction::BHP256HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, U16, u16, to_bits_le) + } + CoreFunction::BHP256HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, U32, u32, to_bits_le) + } + CoreFunction::BHP256HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, U64, u64, to_bits_le) + } + CoreFunction::BHP256HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp256, U128, u128, to_bits_le) + } + CoreFunction::BHP256HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_bhp256, Scalar, to_bits_le) + } + CoreFunction::BHP512CommitToAddress => { + apply_cast2!(TestnetV0::commit_to_group_bhp512, Address) + } + CoreFunction::BHP512CommitToField => { + apply_cast2!(TestnetV0::commit_to_group_bhp512, Field) + } + CoreFunction::BHP512CommitToGroup => { + apply_cast2!(TestnetV0::commit_to_group_bhp512, Group) + } + CoreFunction::BHP512HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_bhp512, Address, to_bits_le) + } + CoreFunction::BHP512HashToField => apply!(TestnetV0::hash_bhp512, Field, to_bits_le), + CoreFunction::BHP512HashToGroup => apply!(TestnetV0::hash_to_group_bhp512, Group, to_bits_le), + CoreFunction::BHP512HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, I8, i8, to_bits_le) + } + CoreFunction::BHP512HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, I16, i16, to_bits_le) + } + CoreFunction::BHP512HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, I32, i32, to_bits_le) + } + CoreFunction::BHP512HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, I64, i64, to_bits_le) + } + CoreFunction::BHP512HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, I128, i128, to_bits_le) + } + CoreFunction::BHP512HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, U8, u8, to_bits_le) + } + CoreFunction::BHP512HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, U16, u16, to_bits_le) + } + CoreFunction::BHP512HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, U32, u32, to_bits_le) + } + CoreFunction::BHP512HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, U64, u64, to_bits_le) + } + CoreFunction::BHP512HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp512, U128, u128, to_bits_le) + } + CoreFunction::BHP512HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_bhp512, Scalar, to_bits_le) + } + CoreFunction::BHP768CommitToAddress => { + apply_cast2!(TestnetV0::commit_to_group_bhp768, Address) + } + CoreFunction::BHP768CommitToField => { + apply_cast2!(TestnetV0::commit_to_group_bhp768, Field) + } + CoreFunction::BHP768CommitToGroup => { + apply_cast2!(TestnetV0::commit_to_group_bhp768, Group) + } + CoreFunction::BHP768HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_bhp768, Address, to_bits_le) + } + CoreFunction::BHP768HashToField => apply!(TestnetV0::hash_bhp768, Field, to_bits_le), + CoreFunction::BHP768HashToGroup => apply!(TestnetV0::hash_to_group_bhp768, Group, to_bits_le), + CoreFunction::BHP768HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, I8, i8, to_bits_le) + } + CoreFunction::BHP768HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, I16, i16, to_bits_le) + } + CoreFunction::BHP768HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, I32, i32, to_bits_le) + } + CoreFunction::BHP768HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, I64, i64, to_bits_le) + } + CoreFunction::BHP768HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, I128, i128, to_bits_le) + } + CoreFunction::BHP768HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, U8, u8, to_bits_le) + } + CoreFunction::BHP768HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, U16, u16, to_bits_le) + } + CoreFunction::BHP768HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, U32, u32, to_bits_le) + } + CoreFunction::BHP768HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, U64, u64, to_bits_le) + } + CoreFunction::BHP768HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp768, U128, u128, to_bits_le) + } + CoreFunction::BHP768HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_bhp768, Scalar, to_bits_le) + } + CoreFunction::BHP1024CommitToAddress => { + apply_cast2!(TestnetV0::commit_to_group_bhp1024, Address) + } + CoreFunction::BHP1024CommitToField => { + apply_cast2!(TestnetV0::commit_to_group_bhp1024, Field) + } + CoreFunction::BHP1024CommitToGroup => { + apply_cast2!(TestnetV0::commit_to_group_bhp1024, Group) + } + CoreFunction::BHP1024HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_bhp1024, Address, to_bits_le) + } + CoreFunction::BHP1024HashToField => apply!(TestnetV0::hash_bhp1024, Field, to_bits_le), + CoreFunction::BHP1024HashToGroup => apply!(TestnetV0::hash_to_group_bhp1024, Group, to_bits_le), + CoreFunction::BHP1024HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I8, i8, to_bits_le) + } + CoreFunction::BHP1024HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I16, i16, to_bits_le) + } + CoreFunction::BHP1024HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I32, i32, to_bits_le) + } + CoreFunction::BHP1024HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I64, i64, to_bits_le) + } + CoreFunction::BHP1024HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, I128, i128, to_bits_le) + } + CoreFunction::BHP1024HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U8, u8, to_bits_le) + } + CoreFunction::BHP1024HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U16, u16, to_bits_le) + } + CoreFunction::BHP1024HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U32, u32, to_bits_le) + } + CoreFunction::BHP1024HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U64, u64, to_bits_le) + } + CoreFunction::BHP1024HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_bhp1024, U128, u128, to_bits_le) + } + CoreFunction::BHP1024HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_bhp1024, Scalar, to_bits_le) + } + CoreFunction::ChaChaRandAddress => Value::Address(self.rng.gen()), + CoreFunction::ChaChaRandBool => Value::Bool(self.rng.gen()), + CoreFunction::ChaChaRandField => Value::Field(self.rng.gen()), + CoreFunction::ChaChaRandGroup => Value::Group(self.rng.gen()), + CoreFunction::ChaChaRandI8 => Value::I8(self.rng.gen()), + CoreFunction::ChaChaRandI16 => Value::I16(self.rng.gen()), + CoreFunction::ChaChaRandI32 => Value::I32(self.rng.gen()), + CoreFunction::ChaChaRandI64 => Value::I64(self.rng.gen()), + CoreFunction::ChaChaRandI128 => Value::I128(self.rng.gen()), + CoreFunction::ChaChaRandU8 => Value::U8(self.rng.gen()), + CoreFunction::ChaChaRandU16 => Value::U16(self.rng.gen()), + CoreFunction::ChaChaRandU32 => Value::U32(self.rng.gen()), + CoreFunction::ChaChaRandU64 => Value::U64(self.rng.gen()), + CoreFunction::ChaChaRandU128 => Value::U128(self.rng.gen()), + CoreFunction::ChaChaRandScalar => Value::Scalar(self.rng.gen()), + CoreFunction::Keccak256HashToAddress => apply_cast!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + Address, + to_bits_le + ), + CoreFunction::Keccak256HashToField => apply_cast!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + Field, + to_bits_le + ), + CoreFunction::Keccak256HashToGroup => { + apply!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + Group, + to_bits_le + ) + } + CoreFunction::Keccak256HashToI8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + I8, + i8, + to_bits_le + ), + CoreFunction::Keccak256HashToI16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + I16, + i16, + to_bits_le + ), + + CoreFunction::Keccak256HashToI32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + I32, + i32, + to_bits_le + ), + CoreFunction::Keccak256HashToI64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + I64, + i64, + to_bits_le + ), + CoreFunction::Keccak256HashToI128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + I128, + i128, + to_bits_le + ), + CoreFunction::Keccak256HashToU8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + U8, + u8, + to_bits_le + ), + CoreFunction::Keccak256HashToU16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + U16, + u16, + to_bits_le + ), + CoreFunction::Keccak256HashToU32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + U32, + u32, + to_bits_le + ), + CoreFunction::Keccak256HashToU64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + U64, + u64, + to_bits_le + ), + CoreFunction::Keccak256HashToU128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + U128, + u128, + to_bits_le + ), + CoreFunction::Keccak256HashToScalar => apply_cast!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_keccak256(v).expect_tc(span)?), + Scalar, + to_bits_le + ), + CoreFunction::Keccak384HashToAddress => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + Address, + to_bits_le + ), + CoreFunction::Keccak384HashToField => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + Field, + to_bits_le + ), + CoreFunction::Keccak384HashToGroup => { + apply!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + Group, + to_bits_le + ) + } + CoreFunction::Keccak384HashToI8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + I8, + i8, + to_bits_le + ), + CoreFunction::Keccak384HashToI16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + I16, + i16, + to_bits_le + ), + CoreFunction::Keccak384HashToI32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + I32, + i32, + to_bits_le + ), + CoreFunction::Keccak384HashToI64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + I64, + i64, + to_bits_le + ), + CoreFunction::Keccak384HashToI128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + I128, + i128, + to_bits_le + ), + CoreFunction::Keccak384HashToU8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + U8, + u8, + to_bits_le + ), + CoreFunction::Keccak384HashToU16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + U16, + u16, + to_bits_le + ), + CoreFunction::Keccak384HashToU32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + U32, + u32, + to_bits_le + ), + CoreFunction::Keccak384HashToU64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + U64, + u64, + to_bits_le + ), + CoreFunction::Keccak384HashToU128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + U128, + u128, + to_bits_le + ), + CoreFunction::Keccak384HashToScalar => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak384(v).expect_tc(span)?), + Scalar, + to_bits_le + ), + CoreFunction::Keccak512HashToAddress => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + Address, + to_bits_le + ), + CoreFunction::Keccak512HashToField => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + Field, + to_bits_le + ), + CoreFunction::Keccak512HashToGroup => { + apply!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + Group, + to_bits_le + ) + } + CoreFunction::Keccak512HashToI8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + I8, + i8, + to_bits_le + ), + CoreFunction::Keccak512HashToI16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + I16, + i16, + to_bits_le + ), + CoreFunction::Keccak512HashToI32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + I32, + i32, + to_bits_le + ), + CoreFunction::Keccak512HashToI64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + I64, + i64, + to_bits_le + ), + CoreFunction::Keccak512HashToI128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + I128, + i128, + to_bits_le + ), + CoreFunction::Keccak512HashToU8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + U8, + u8, + to_bits_le + ), + CoreFunction::Keccak512HashToU16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + U16, + u16, + to_bits_le + ), + CoreFunction::Keccak512HashToU32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + U32, + u32, + to_bits_le + ), + CoreFunction::Keccak512HashToU64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + U64, + u64, + to_bits_le + ), + CoreFunction::Keccak512HashToU128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + U128, + u128, + to_bits_le + ), + CoreFunction::Keccak512HashToScalar => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_keccak512(v).expect_tc(span)?), + Scalar, + to_bits_le + ), + CoreFunction::Pedersen64CommitToAddress => { + apply_cast2!(TestnetV0::commit_to_group_ped64, Address) + } + CoreFunction::Pedersen64CommitToField => { + apply_cast2!(TestnetV0::commit_to_group_ped64, Field) + } + CoreFunction::Pedersen64CommitToGroup => { + apply_cast2!(TestnetV0::commit_to_group_ped64, Group) + } + CoreFunction::Pedersen64HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_ped64, Address, to_bits_le) + } + CoreFunction::Pedersen64HashToField => apply!(TestnetV0::hash_ped64, Field, to_bits_le), + CoreFunction::Pedersen64HashToGroup => apply!(TestnetV0::hash_to_group_ped64, Group, to_bits_le), + CoreFunction::Pedersen64HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, I8, i8, to_bits_le) + } + CoreFunction::Pedersen64HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, I16, i16, to_bits_le) + } + CoreFunction::Pedersen64HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, I32, i32, to_bits_le) + } + CoreFunction::Pedersen64HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, I64, i64, to_bits_le) + } + CoreFunction::Pedersen64HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, I128, i128, to_bits_le) + } + CoreFunction::Pedersen64HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, U8, u8, to_bits_le) + } + CoreFunction::Pedersen64HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, U16, u16, to_bits_le) + } + CoreFunction::Pedersen64HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, U32, u32, to_bits_le) + } + CoreFunction::Pedersen64HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, U64, u64, to_bits_le) + } + CoreFunction::Pedersen64HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, U128, u128, to_bits_le) + } + CoreFunction::Pedersen64HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_ped64, Scalar, to_bits_le) + } + CoreFunction::Pedersen128HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_ped128, Address, to_bits_le) + } + CoreFunction::Pedersen128HashToField => { + apply_cast!(TestnetV0::hash_to_group_ped128, Field, to_bits_le) + } + CoreFunction::Pedersen128HashToGroup => { + apply_cast!(TestnetV0::hash_to_group_ped128, Group, to_bits_le) + } + CoreFunction::Pedersen128HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_ped128, I8, i8, to_bits_le) + } + CoreFunction::Pedersen128HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, I16, i16, to_bits_le) + } + CoreFunction::Pedersen128HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_ped128, I32, i32, to_bits_le) + } + CoreFunction::Pedersen128HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, I64, i64, to_bits_le) + } + CoreFunction::Pedersen128HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_ped128, I128, i128, to_bits_le) + } + CoreFunction::Pedersen128HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_ped128, U8, u8, to_bits_le) + } + CoreFunction::Pedersen128HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, U16, u16, to_bits_le) + } + CoreFunction::Pedersen128HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_ped128, U32, u32, to_bits_le) + } + CoreFunction::Pedersen128HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_ped64, U64, u64, to_bits_le) + } + CoreFunction::Pedersen128HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_ped128, U128, u128, to_bits_le) + } + CoreFunction::Pedersen128HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_ped128, Scalar, to_bits_le) + } + CoreFunction::Pedersen128CommitToAddress => { + apply_cast2!(TestnetV0::commit_to_group_ped128, Address) + } + CoreFunction::Pedersen128CommitToField => { + apply_cast2!(TestnetV0::commit_to_group_ped128, Field) + } + CoreFunction::Pedersen128CommitToGroup => { + apply_cast2!(TestnetV0::commit_to_group_ped128, Group) + } + CoreFunction::Poseidon2HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_psd2, Address, to_fields) + } + CoreFunction::Poseidon2HashToField => { + apply_cast!(TestnetV0::hash_to_group_psd2, Field, to_fields) + } + CoreFunction::Poseidon2HashToGroup => { + apply_cast!(TestnetV0::hash_to_group_psd2, Group, to_fields) + } + CoreFunction::Poseidon2HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, I8, i8, to_fields) + } + CoreFunction::Poseidon2HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, I16, i16, to_fields) + } + CoreFunction::Poseidon2HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, I32, i32, to_fields) + } + CoreFunction::Poseidon2HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, I64, i64, to_fields) + } + CoreFunction::Poseidon2HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, I128, i128, to_fields) + } + CoreFunction::Poseidon2HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, U8, u8, to_fields) + } + CoreFunction::Poseidon2HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, U16, u16, to_fields) + } + CoreFunction::Poseidon2HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, U32, u32, to_fields) + } + CoreFunction::Poseidon2HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, U64, u64, to_fields) + } + CoreFunction::Poseidon2HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_psd2, U128, u128, to_fields) + } + CoreFunction::Poseidon2HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_psd4, Scalar, to_fields) + } + CoreFunction::Poseidon4HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_psd4, Address, to_fields) + } + CoreFunction::Poseidon4HashToField => { + apply_cast!(TestnetV0::hash_to_group_psd4, Field, to_fields) + } + CoreFunction::Poseidon4HashToGroup => { + apply_cast!(TestnetV0::hash_to_group_psd4, Group, to_fields) + } + CoreFunction::Poseidon4HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, I8, i8, to_fields) + } + CoreFunction::Poseidon4HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, I16, i16, to_fields) + } + CoreFunction::Poseidon4HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, I32, i32, to_fields) + } + CoreFunction::Poseidon4HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, I64, i64, to_fields) + } + CoreFunction::Poseidon4HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, I128, i128, to_fields) + } + CoreFunction::Poseidon4HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, U8, u8, to_fields) + } + CoreFunction::Poseidon4HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, U16, u16, to_fields) + } + CoreFunction::Poseidon4HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, U32, u32, to_fields) + } + CoreFunction::Poseidon4HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, U64, u64, to_fields) + } + CoreFunction::Poseidon4HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_psd4, U128, u128, to_fields) + } + CoreFunction::Poseidon4HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_psd4, Scalar, to_fields) + } + CoreFunction::Poseidon8HashToAddress => { + apply_cast!(TestnetV0::hash_to_group_psd8, Address, to_fields) + } + CoreFunction::Poseidon8HashToField => { + apply_cast!(TestnetV0::hash_to_group_psd8, Field, to_fields) + } + CoreFunction::Poseidon8HashToGroup => { + apply_cast!(TestnetV0::hash_to_group_psd8, Group, to_fields) + } + CoreFunction::Poseidon8HashToI8 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, I8, i8, to_fields) + } + CoreFunction::Poseidon8HashToI16 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, I16, i16, to_fields) + } + CoreFunction::Poseidon8HashToI32 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, I32, i32, to_fields) + } + CoreFunction::Poseidon8HashToI64 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, I64, i64, to_fields) + } + CoreFunction::Poseidon8HashToI128 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, I128, i128, to_fields) + } + CoreFunction::Poseidon8HashToU8 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, U8, u8, to_fields) + } + CoreFunction::Poseidon8HashToU16 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, U16, u16, to_fields) + } + CoreFunction::Poseidon8HashToU32 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, U32, u32, to_fields) + } + CoreFunction::Poseidon8HashToU64 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, U64, u64, to_fields) + } + CoreFunction::Poseidon8HashToU128 => { + apply_cast_int!(TestnetV0::hash_to_group_psd8, U128, u128, to_fields) + } + CoreFunction::Poseidon8HashToScalar => { + apply_cast!(TestnetV0::hash_to_group_psd8, Scalar, to_fields) + } + CoreFunction::SHA3_256HashToAddress => apply_cast!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + Address, + to_bits_le + ), + CoreFunction::SHA3_256HashToField => apply_cast!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + Field, + to_bits_le + ), + CoreFunction::SHA3_256HashToGroup => apply_cast!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + Group, + to_bits_le + ), + CoreFunction::SHA3_256HashToI8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + I8, + i8, + to_bits_le + ), + CoreFunction::SHA3_256HashToI16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + I16, + i16, + to_bits_le + ), + CoreFunction::SHA3_256HashToI32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + I32, + i32, + to_bits_le + ), + CoreFunction::SHA3_256HashToI64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + I64, + i64, + to_bits_le + ), + CoreFunction::SHA3_256HashToI128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + I128, + i128, + to_bits_le + ), + CoreFunction::SHA3_256HashToU8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + U8, + u8, + to_bits_le + ), + CoreFunction::SHA3_256HashToU16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + U16, + u16, + to_bits_le + ), + CoreFunction::SHA3_256HashToU32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + U32, + u32, + to_bits_le + ), + CoreFunction::SHA3_256HashToU64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + U64, + u64, + to_bits_le + ), + CoreFunction::SHA3_256HashToU128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + U128, + u128, + to_bits_le + ), + CoreFunction::SHA3_256HashToScalar => apply_cast!( + |v| TestnetV0::hash_to_group_bhp256(&TestnetV0::hash_sha3_256(v).expect_tc(span)?), + Scalar, + to_bits_le + ), + CoreFunction::SHA3_384HashToAddress => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + Address, + to_bits_le + ), + CoreFunction::SHA3_384HashToField => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + Field, + to_bits_le + ), + CoreFunction::SHA3_384HashToGroup => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + Group, + to_bits_le + ), + CoreFunction::SHA3_384HashToI8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + I8, + i8, + to_bits_le + ), + CoreFunction::SHA3_384HashToI16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + I16, + i16, + to_bits_le + ), + CoreFunction::SHA3_384HashToI32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + I32, + i32, + to_bits_le + ), + CoreFunction::SHA3_384HashToI64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + I64, + i64, + to_bits_le + ), + CoreFunction::SHA3_384HashToI128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + I128, + i128, + to_bits_le + ), + CoreFunction::SHA3_384HashToU8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + U8, + u8, + to_bits_le + ), + CoreFunction::SHA3_384HashToU16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + U16, + u16, + to_bits_le + ), + CoreFunction::SHA3_384HashToU32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + U32, + u32, + to_bits_le + ), + CoreFunction::SHA3_384HashToU64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + U64, + u64, + to_bits_le + ), + CoreFunction::SHA3_384HashToU128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + U128, + u128, + to_bits_le + ), + CoreFunction::SHA3_384HashToScalar => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_384(v).expect_tc(span)?), + Scalar, + to_bits_le + ), + CoreFunction::SHA3_512HashToAddress => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + Address, + to_bits_le + ), + CoreFunction::SHA3_512HashToField => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + Field, + to_bits_le + ), + CoreFunction::SHA3_512HashToGroup => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + Group, + to_bits_le + ), + CoreFunction::SHA3_512HashToI8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + I8, + i8, + to_bits_le + ), + CoreFunction::SHA3_512HashToI16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + I16, + i16, + to_bits_le + ), + CoreFunction::SHA3_512HashToI32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + I32, + i32, + to_bits_le + ), + CoreFunction::SHA3_512HashToI64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + I64, + i64, + to_bits_le + ), + CoreFunction::SHA3_512HashToI128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + I128, + i128, + to_bits_le + ), + CoreFunction::SHA3_512HashToU8 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + U8, + u8, + to_bits_le + ), + CoreFunction::SHA3_512HashToU16 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + U16, + u16, + to_bits_le + ), + CoreFunction::SHA3_512HashToU32 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + U32, + u32, + to_bits_le + ), + CoreFunction::SHA3_512HashToU64 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + U64, + u64, + to_bits_le + ), + CoreFunction::SHA3_512HashToU128 => apply_cast_int!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + U128, + u128, + to_bits_le + ), + CoreFunction::SHA3_512HashToScalar => apply_cast!( + |v| TestnetV0::hash_to_group_bhp512(&TestnetV0::hash_sha3_512(v).expect_tc(span)?), + Scalar, + to_bits_le + ), + CoreFunction::MappingGet => { + let key = self.values.pop().expect_tc(span)?; + let (program, name) = match &arguments[0] { + Expression::Identifier(id) => (None, id.name), + Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), + _ => tc_fail!(), + }; + match self.lookup_mapping(program, name).and_then(|mapping| mapping.get(&key)) { + Some(v) => v.clone(), + None => halt!(span, "map lookup failure"), + } + } + CoreFunction::MappingGetOrUse => { + let use_value = self.values.pop().expect_tc(span)?; + let key = self.values.pop().expect_tc(span)?; + let (program, name) = match &arguments[0] { + Expression::Identifier(id) => (None, id.name), + Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), + _ => tc_fail!(), + }; + match self.lookup_mapping(program, name).and_then(|mapping| mapping.get(&key)) { + Some(v) => v.clone(), + None => use_value, + } + } + CoreFunction::MappingSet => { + let value = self.pop_value()?; + let key = self.pop_value()?; + let (program, name) = match &arguments[0] { + Expression::Identifier(id) => (None, id.name), + Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), + _ => tc_fail!(), + }; + if let Some(mapping) = self.lookup_mapping_mut(program, name) { + mapping.insert(key, value); + } else { + tc_fail!(); + } + Value::Unit + } + CoreFunction::MappingRemove => { + let key = self.pop_value()?; + let (program, name) = match &arguments[0] { + Expression::Identifier(id) => (None, id.name), + Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), + _ => tc_fail!(), + }; + if let Some(mapping) = self.lookup_mapping_mut(program, name) { + mapping.remove(&key); + } else { + tc_fail!(); + } + Value::Unit + } + CoreFunction::MappingContains => { + let key = self.pop_value()?; + let (program, name) = match &arguments[0] { + Expression::Identifier(id) => (None, id.name), + Expression::Locator(locator) => (Some(locator.program.name.name), locator.name), + _ => tc_fail!(), + }; + if let Some(mapping) = self.lookup_mapping_mut(program, name) { + Value::Bool(mapping.contains_key(&key)) + } else { + tc_fail!(); + } + } + CoreFunction::GroupToXCoordinate => { + let Value::Group(g) = self.pop_value()? else { + tc_fail!(); + }; + Value::Field(g.to_x_coordinate()) + } + CoreFunction::GroupToYCoordinate => { + let Value::Group(g) = self.pop_value()? else { + tc_fail!(); + }; + Value::Field(g.to_y_coordinate()) + } + CoreFunction::SignatureVerify => todo!(), + CoreFunction::FutureAwait => { + let Value::Future(future) = self.pop_value()? else { + tc_fail!(); + }; + self.contexts.add_future(future); + Value::Unit + } + }; + + Ok(value) + } } #[derive(Clone, Debug)] @@ -1970,7 +2114,7 @@ pub struct StepResult { } /// Evaluate a binary operation. -fn evaluate_binary(span: Span, op: BinaryOperation, lhs: Value, rhs: Value) -> Result { +pub fn evaluate_binary(span: Span, op: BinaryOperation, lhs: Value, rhs: Value) -> Result { let value = match op { BinaryOperation::Add => { let Some(value) = (match (lhs, rhs) { @@ -2389,7 +2533,7 @@ fn evaluate_binary(span: Span, op: BinaryOperation, lhs: Value, rhs: Value) -> R } /// Evaluate a unary operation. -fn evaluate_unary(span: Span, op: UnaryOperation, value: Value) -> Result { +pub fn evaluate_unary(span: Span, op: UnaryOperation, value: Value) -> Result { let value_result = match op { UnaryOperation::Abs => match value { Value::I8(x) => { diff --git a/interpreter/src/cursor_aleo.rs b/interpreter/src/cursor_aleo.rs new file mode 100644 index 0000000000..bbb13a3836 --- /dev/null +++ b/interpreter/src/cursor_aleo.rs @@ -0,0 +1,886 @@ +// Copyright (C) 2019-2024 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use super::*; + +use leo_ast::{BinaryOperation, CoreFunction, IntegerType, Type, UnaryOperation}; + +use snarkvm::{ + prelude::{Boolean, Identifier, Literal, LiteralType, PlaintextType, Register, TestnetV0, integers::Integer}, + synthesizer::{Command, Instruction}, +}; +use snarkvm_synthesizer_program::{CallOperator, CastType, Operand}; + +use std::mem; + +impl Cursor<'_> { + fn get_register(&self, reg: Register) -> &Value { + let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last() else { + panic!(); + }; + match reg { + Register::Locator(index) => { + registers.get(&index).expect("valid .aleo code doesn't access undefined registers") + } + Register::Access(_, _) => todo!(), + } + } + + fn set_register(&mut self, reg: Register, value: Value) { + let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last_mut() else { + panic!(); + }; + + match reg { + Register::Locator(index) => { + registers.insert(index, value); + } + Register::Access(_, _) => todo!(), + } + } + + fn instructions_len(&self) -> usize { + let Some(Frame { element: Element::AleoExecution { context, .. }, .. }) = self.frames.last() else { + panic!(); + }; + match context { + AleoContext::Closure(closure) => closure.instructions().len(), + AleoContext::Function(function) => function.instructions().len(), + AleoContext::Finalize(finalize) => finalize.commands().len(), + } + } + + fn increment_instruction_index(&mut self) { + let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last_mut() + else { + panic!(); + }; + *instruction_index += 1; + } + + fn execution_complete(&self) -> bool { + let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last() else { + panic!(); + }; + *instruction_index >= self.instructions_len() + } + + fn next_instruction(&self) -> Option<&Instruction> { + let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last() + else { + panic!(); + }; + match context { + AleoContext::Closure(closure) => closure.instructions().get(*instruction_index), + AleoContext::Function(function) => function.instructions().get(*instruction_index), + AleoContext::Finalize(_) => None, + } + } + + fn next_command(&self) -> Option<&Command> { + let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last() + else { + panic!(); + }; + match context { + AleoContext::Closure(_) | AleoContext::Function(_) => None, + AleoContext::Finalize(finalize) => finalize.commands().get(*instruction_index), + } + } + + fn operand_value(&self, operand: &Operand) -> Value { + match operand { + Operand::Literal(literal) => match literal { + Literal::Address(x) => Value::Address(*x), + Literal::Boolean(x) => Value::Bool(**x), + Literal::Field(x) => Value::Field(*x), + Literal::Group(x) => Value::Group(*x), + Literal::I8(x) => Value::I8(**x), + Literal::I16(x) => Value::I16(**x), + Literal::I32(x) => Value::I32(**x), + Literal::I64(x) => Value::I64(**x), + Literal::I128(x) => Value::I128(**x), + Literal::U8(x) => Value::U8(**x), + Literal::U16(x) => Value::U16(**x), + Literal::U32(x) => Value::U32(**x), + Literal::U64(x) => Value::U64(**x), + Literal::U128(x) => Value::U128(**x), + Literal::Scalar(x) => Value::Scalar(*x), + Literal::Signature(_) => todo!(), + Literal::String(_) => todo!(), + }, + Operand::Register(register) => self.get_register(register.clone()).clone(), + Operand::ProgramID(_) => todo!(), + Operand::Signer => Value::Address(self.signer), + Operand::Caller => { + if let Some(function_context) = self.contexts.last() { + Value::Address(function_context.caller) + } else { + Value::Address(self.signer) + } + } + Operand::BlockHeight => Value::U32(self.block_height), + Operand::NetworkID => todo!(), + } + } + + fn step_aleo_instruction(&mut self, instruction: Instruction) -> Result<()> { + // The Aleo VM code is a linear sequence of instructions, so we don't need to keep + // a stack of Elements (except for calls). Just run instructions in order. + use Instruction::*; + + let Some(Frame { step, .. }) = self.frames.last() else { + panic!("frame expected"); + }; + + macro_rules! unary { + ($svm_op: expr, $op: ident) => {{ + let operand = self.operand_value(&$svm_op.operands()[0]); + let value = evaluate_unary(Default::default(), UnaryOperation::$op, operand)?; + self.increment_instruction_index(); + (value, $svm_op.destinations()[0].clone()) + }}; + } + + macro_rules! binary { + ($svm_op: expr, $op: ident) => {{ + let operand0 = self.operand_value(&$svm_op.operands()[0]); + let operand1 = self.operand_value(&$svm_op.operands()[1]); + let value = evaluate_binary(Default::default(), BinaryOperation::$op, operand0, operand1)?; + self.increment_instruction_index(); + (value, $svm_op.destinations()[0].clone()) + }}; + } + + macro_rules! commit_function { + ($commit: expr, + $to_address: ident, + $to_field: ident, + $to_group: ident, + ) => {{ + let core_function = match $commit.destination_type() { + LiteralType::Address => CoreFunction::$to_address, + LiteralType::Field => CoreFunction::$to_field, + LiteralType::Group => CoreFunction::$to_group, + _ => panic!("invalid commit destination type"), + }; + + let randomizer_value = self.operand_value(&$commit.operands()[0]); + let operand_value = self.operand_value(&$commit.operands()[1]); + self.values.push(randomizer_value); + self.values.push(operand_value); + let value = self.evaluate_core_function(core_function, &[], Span::default())?; + self.increment_instruction_index(); + (value, $commit.destinations()[0].clone()) + }}; + } + + macro_rules! hash_function { + ($hash: expr, + $to_address: ident, + $to_field: ident, + $to_group: ident, + $to_i8: ident, + $to_i16: ident, + $to_i32: ident, + $to_i64: ident, + $to_i128: ident, + $to_u8: ident, + $to_u16: ident, + $to_u32: ident, + $to_u64: ident, + $to_u128: ident, + $to_scalar: ident, + ) => {{ + let core_function = match $hash.destination_type() { + PlaintextType::Literal(LiteralType::Address) => CoreFunction::$to_address, + PlaintextType::Literal(LiteralType::Field) => CoreFunction::$to_field, + PlaintextType::Literal(LiteralType::Group) => CoreFunction::$to_group, + PlaintextType::Literal(LiteralType::I8) => CoreFunction::$to_i8, + PlaintextType::Literal(LiteralType::I16) => CoreFunction::$to_i16, + PlaintextType::Literal(LiteralType::I32) => CoreFunction::$to_i32, + PlaintextType::Literal(LiteralType::I64) => CoreFunction::$to_i64, + PlaintextType::Literal(LiteralType::I128) => CoreFunction::$to_i128, + PlaintextType::Literal(LiteralType::U8) => CoreFunction::$to_u8, + PlaintextType::Literal(LiteralType::U16) => CoreFunction::$to_u16, + PlaintextType::Literal(LiteralType::U32) => CoreFunction::$to_u32, + PlaintextType::Literal(LiteralType::U64) => CoreFunction::$to_u64, + PlaintextType::Literal(LiteralType::U128) => CoreFunction::$to_u128, + PlaintextType::Literal(LiteralType::Scalar) => CoreFunction::$to_scalar, + _ => panic!("invalid hash destination type"), + }; + let operand_value = self.operand_value(&$hash.operands()[0]); + self.values.push(operand_value); + let value = self.evaluate_core_function(core_function, &[], Span::default())?; + self.increment_instruction_index(); + (value, $hash.destinations()[0].clone()) + }}; + } + + let (value, destination) = match instruction { + Abs(abs) => unary!(abs, Abs), + AbsWrapped(abs_wrapped) => unary!(abs_wrapped, AbsWrapped), + Add(add) => binary!(add, Add), + AddWrapped(add_wrapped) => binary!(add_wrapped, AddWrapped), + And(and) => binary!(and, BitwiseAnd), + AssertEq(assert_eq) => { + let operand0 = self.operand_value(&assert_eq.operands()[0]); + let operand1 = self.operand_value(&assert_eq.operands()[1]); + if operand0.neq(&operand1) { + halt_no_span!("assertion failure: {operand0} != {operand1}"); + } + self.increment_instruction_index(); + return Ok(()); + } + AssertNeq(assert_neq) => { + let operand0 = self.operand_value(&assert_neq.operands()[0]); + let operand1 = self.operand_value(&assert_neq.operands()[1]); + if operand0.eq(&operand1) { + halt_no_span!("assertion failure: {operand0} != {operand1}"); + } + self.increment_instruction_index(); + return Ok(()); + } + Async(async_) if *step == 0 => { + let program = self.contexts.current_program().expect("there should be a program"); + let name = snarkvm_identifier_to_symbol(async_.function_name()); + let arguments: Vec = async_.operands().iter().map(|op| self.operand_value(op)).collect(); + if self.really_async { + let async_ex = AsyncExecution { function: GlobalId { name, program }, arguments }; + (Value::Future(Future(vec![async_ex])), async_.destinations()[0].clone()) + } else { + self.do_call( + program, + name, + arguments.into_iter(), + true, // finalize + Span::default(), + )?; + self.increment_step(); + return Ok(()); + } + } + Call(call) if *step == 0 => { + let (program, name) = match call.operator() { + CallOperator::Locator(locator) => ( + snarkvm_identifier_to_symbol(locator.resource()), + snarkvm_identifier_to_symbol(locator.program_id().name()), + ), + CallOperator::Resource(id) => ( + snarkvm_identifier_to_symbol(id), + self.contexts.current_program().expect("there should be a program"), + ), + }; + let arguments: Vec = call.operands().iter().map(|op| self.operand_value(op)).collect(); + self.do_call( + program, + name, + arguments.into_iter(), + false, // finalize + Span::default(), + )?; + self.increment_step(); + return Ok(()); + } + Async(async_) if *step == 1 => { + // We've done a call, and the result is on the value stack. + self.values.pop(); + self.set_register(async_.destinations()[0].clone(), Value::Future(Future(Vec::new()))); + self.increment_instruction_index(); + return Ok(()); + } + Call(call) if *step == 1 => { + // We've done a call, and the result is on the value stack. + let Some(result) = self.values.pop() else { + panic!("should have a result"); + }; + if call.destinations().len() == 1 { + self.set_register(call.destinations()[0].clone(), result); + } else { + let Value::Tuple(tuple) = result else { + panic!("function returning multiple values should create a tuple"); + }; + for (dest, value) in call.destinations().iter().zip(tuple.into_iter()) { + self.set_register(dest.clone(), value); + } + } + self.increment_instruction_index(); + return Ok(()); + } + Call(_) | Async(_) => unreachable!("all cases covered above"), + Cast(cast) => { + let destination = cast.destinations()[0].clone(); + + self.increment_instruction_index(); + + let make_struct = |program, name_identifier| { + let name = snarkvm_identifier_to_symbol(name_identifier); + let id = GlobalId { program, name }; + let struct_type = self.structs.get(&id).expect("struct type should exist"); + let operands = cast.operands().iter().map(|op| self.operand_value(op)); + Value::Struct(StructContents { + name, + contents: struct_type.iter().cloned().zip(operands).collect(), + }) + }; + + match cast.cast_type() { + CastType::GroupXCoordinate => { + let Value::Group(g) = self.operand_value(&cast.operands()[0]) else { + tc_fail!(); + }; + let value = Value::Field(g.to_x_coordinate()); + (value, destination) + } + CastType::GroupYCoordinate => { + let Value::Group(g) = self.operand_value(&cast.operands()[0]) else { + tc_fail!(); + }; + let value = Value::Field(g.to_y_coordinate()); + (value, destination) + } + CastType::Plaintext(PlaintextType::Array(_array)) => { + let value = Value::Array(cast.operands().iter().map(|op| self.operand_value(op)).collect()); + (value, destination) + } + CastType::Plaintext(PlaintextType::Literal(literal_type)) => { + let operand = self.operand_value(&cast.operands()[0]); + let value = match operand.cast(&snarkvm_literal_type_to_type(*literal_type)) { + Some(value) => value, + None => halt_no_span!("cast failure"), + }; + (value, destination) + } + CastType::Record(struct_name) | CastType::Plaintext(PlaintextType::Struct(struct_name)) => { + let program = self.contexts.current_program().expect("there should be a current program"); + let value = make_struct(program, struct_name); + (value, destination) + } + CastType::ExternalRecord(locator) => { + let program = snarkvm_identifier_to_symbol(locator.program_id().name()); + let value = make_struct(program, locator.name()); + (value, destination) + } + } + } + CastLossy(cast_lossy) => { + match cast_lossy.cast_type() { + CastType::Plaintext(PlaintextType::Literal(literal_type)) => { + // This is the only variant supported for lossy casts. + let operand = self.operand_value(&cast_lossy.operands()[0]); + let operand_literal = value_to_snarkvm_literal(operand); + let result_literal = match operand_literal.cast_lossy(*literal_type) { + Ok(result_literal) => result_literal, + Err(_) => halt_no_span!("cast failure"), + }; + let destination = cast_lossy.destinations()[0].clone(); + self.increment_instruction_index(); + (snarkvm_literal_to_value(result_literal), destination) + } + _ => tc_fail!(), + } + } + CommitBHP256(commit) => { + commit_function!(commit, BHP256CommitToAddress, BHP256CommitToField, BHP256CommitToGroup,) + } + CommitBHP512(commit) => { + commit_function!(commit, BHP512CommitToAddress, BHP512CommitToField, BHP512CommitToGroup,) + } + CommitBHP768(commit) => { + commit_function!(commit, BHP768CommitToAddress, BHP768CommitToField, BHP768CommitToGroup,) + } + CommitBHP1024(commit) => { + commit_function!(commit, BHP1024CommitToAddress, BHP1024CommitToField, BHP1024CommitToGroup,) + } + CommitPED64(commit) => { + commit_function!(commit, Pedersen64CommitToAddress, Pedersen64CommitToField, Pedersen64CommitToGroup,) + } + CommitPED128(commit) => { + commit_function!(commit, Pedersen128CommitToAddress, Pedersen128CommitToField, Pedersen128CommitToGroup,) + } + Div(div) => binary!(div, Div), + DivWrapped(div_wrapped) => binary!(div_wrapped, DivWrapped), + Double(double) => unary!(double, Double), + GreaterThan(gt) => binary!(gt, Gt), + GreaterThanOrEqual(gte) => binary!(gte, Gte), + HashBHP256(hash) => hash_function!( + hash, + BHP256HashToAddress, + BHP256HashToField, + BHP256HashToGroup, + BHP256HashToI8, + BHP256HashToI16, + BHP256HashToI32, + BHP256HashToI64, + BHP256HashToI128, + BHP256HashToU8, + BHP256HashToU16, + BHP256HashToU32, + BHP256HashToU64, + BHP256HashToU128, + BHP256HashToScalar, + ), + HashBHP512(hash) => hash_function!( + hash, + BHP512HashToAddress, + BHP512HashToField, + BHP512HashToGroup, + BHP512HashToI8, + BHP512HashToI16, + BHP512HashToI32, + BHP512HashToI64, + BHP512HashToI128, + BHP512HashToU8, + BHP512HashToU16, + BHP512HashToU32, + BHP512HashToU64, + BHP512HashToU128, + BHP512HashToScalar, + ), + HashBHP768(hash) => hash_function!( + hash, + BHP768HashToAddress, + BHP768HashToField, + BHP768HashToGroup, + BHP768HashToI8, + BHP768HashToI16, + BHP768HashToI32, + BHP768HashToI64, + BHP768HashToI128, + BHP768HashToU8, + BHP768HashToU16, + BHP768HashToU32, + BHP768HashToU64, + BHP768HashToU128, + BHP768HashToScalar, + ), + HashBHP1024(hash) => hash_function!( + hash, + BHP1024HashToAddress, + BHP1024HashToField, + BHP1024HashToGroup, + BHP1024HashToI8, + BHP1024HashToI16, + BHP1024HashToI32, + BHP1024HashToI64, + BHP1024HashToI128, + BHP1024HashToU8, + BHP1024HashToU16, + BHP1024HashToU32, + BHP1024HashToU64, + BHP1024HashToU128, + BHP1024HashToScalar, + ), + HashKeccak256(hash) => hash_function!( + hash, + Keccak256HashToAddress, + Keccak256HashToField, + Keccak256HashToGroup, + Keccak256HashToI8, + Keccak256HashToI16, + Keccak256HashToI32, + Keccak256HashToI64, + Keccak256HashToI128, + Keccak256HashToU8, + Keccak256HashToU16, + Keccak256HashToU32, + Keccak256HashToU64, + Keccak256HashToU128, + Keccak256HashToScalar, + ), + HashKeccak384(hash) => hash_function!( + hash, + Keccak384HashToAddress, + Keccak384HashToField, + Keccak384HashToGroup, + Keccak384HashToI8, + Keccak384HashToI16, + Keccak384HashToI32, + Keccak384HashToI64, + Keccak384HashToI128, + Keccak384HashToU8, + Keccak384HashToU16, + Keccak384HashToU32, + Keccak384HashToU64, + Keccak384HashToU128, + Keccak384HashToScalar, + ), + HashKeccak512(hash) => hash_function!( + hash, + Keccak512HashToAddress, + Keccak512HashToField, + Keccak512HashToGroup, + Keccak512HashToI8, + Keccak512HashToI16, + Keccak512HashToI32, + Keccak512HashToI64, + Keccak512HashToI128, + Keccak512HashToU8, + Keccak512HashToU16, + Keccak512HashToU32, + Keccak512HashToU64, + Keccak512HashToU128, + Keccak512HashToScalar, + ), + HashPED64(hash) => hash_function!( + hash, + Pedersen64HashToAddress, + Pedersen64HashToField, + Pedersen64HashToGroup, + Pedersen64HashToI8, + Pedersen64HashToI16, + Pedersen64HashToI32, + Pedersen64HashToI64, + Pedersen64HashToI128, + Pedersen64HashToU8, + Pedersen64HashToU16, + Pedersen64HashToU32, + Pedersen64HashToU64, + Pedersen64HashToU128, + Pedersen64HashToScalar, + ), + HashPED128(hash) => hash_function!( + hash, + Pedersen128HashToAddress, + Pedersen128HashToField, + Pedersen128HashToGroup, + Pedersen128HashToI8, + Pedersen128HashToI16, + Pedersen128HashToI32, + Pedersen128HashToI64, + Pedersen128HashToI128, + Pedersen128HashToU8, + Pedersen128HashToU16, + Pedersen128HashToU32, + Pedersen128HashToU64, + Pedersen128HashToU128, + Pedersen128HashToScalar, + ), + HashPSD2(hash) => hash_function!( + hash, + Poseidon2HashToAddress, + Poseidon2HashToField, + Poseidon2HashToGroup, + Poseidon2HashToI8, + Poseidon2HashToI16, + Poseidon2HashToI32, + Poseidon2HashToI64, + Poseidon2HashToI128, + Poseidon2HashToU8, + Poseidon2HashToU16, + Poseidon2HashToU32, + Poseidon2HashToU64, + Poseidon2HashToU128, + Poseidon2HashToScalar, + ), + HashPSD4(hash) => hash_function!( + hash, + Poseidon4HashToAddress, + Poseidon4HashToField, + Poseidon4HashToGroup, + Poseidon4HashToI8, + Poseidon4HashToI16, + Poseidon4HashToI32, + Poseidon4HashToI64, + Poseidon4HashToI128, + Poseidon4HashToU8, + Poseidon4HashToU16, + Poseidon4HashToU32, + Poseidon4HashToU64, + Poseidon4HashToU128, + Poseidon4HashToScalar, + ), + HashPSD8(hash) => hash_function!( + hash, + Poseidon8HashToAddress, + Poseidon8HashToField, + Poseidon8HashToGroup, + Poseidon8HashToI8, + Poseidon8HashToI16, + Poseidon8HashToI32, + Poseidon8HashToI64, + Poseidon8HashToI128, + Poseidon8HashToU8, + Poseidon8HashToU16, + Poseidon8HashToU32, + Poseidon8HashToU64, + Poseidon8HashToU128, + Poseidon8HashToScalar, + ), + HashSha3_256(hash) => hash_function!( + hash, + SHA3_256HashToAddress, + SHA3_256HashToField, + SHA3_256HashToGroup, + SHA3_256HashToI8, + SHA3_256HashToI16, + SHA3_256HashToI32, + SHA3_256HashToI64, + SHA3_256HashToI128, + SHA3_256HashToU8, + SHA3_256HashToU16, + SHA3_256HashToU32, + SHA3_256HashToU64, + SHA3_256HashToU128, + SHA3_256HashToScalar, + ), + HashSha3_384(hash) => hash_function!( + hash, + SHA3_384HashToAddress, + SHA3_384HashToField, + SHA3_384HashToGroup, + SHA3_384HashToI8, + SHA3_384HashToI16, + SHA3_384HashToI32, + SHA3_384HashToI64, + SHA3_384HashToI128, + SHA3_384HashToU8, + SHA3_384HashToU16, + SHA3_384HashToU32, + SHA3_384HashToU64, + SHA3_384HashToU128, + SHA3_384HashToScalar, + ), + HashSha3_512(hash) => hash_function!( + hash, + SHA3_512HashToAddress, + SHA3_512HashToField, + SHA3_512HashToGroup, + SHA3_512HashToI8, + SHA3_512HashToI16, + SHA3_512HashToI32, + SHA3_512HashToI64, + SHA3_512HashToI128, + SHA3_512HashToU8, + SHA3_512HashToU16, + SHA3_512HashToU32, + SHA3_512HashToU64, + SHA3_512HashToU128, + SHA3_512HashToScalar, + ), + HashManyPSD2(_) | HashManyPSD4(_) | HashManyPSD8(_) => panic!("these instructions don't exist yet"), + Inv(inv) => unary!(inv, Inverse), + IsEq(eq) => binary!(eq, Eq), + IsNeq(neq) => binary!(neq, Neq), + LessThan(lt) => binary!(lt, Lt), + LessThanOrEqual(lte) => binary!(lte, Lte), + Modulo(modulo) => binary!(modulo, Mod), + Mul(mul) => binary!(mul, Mul), + MulWrapped(mul_wrapped) => binary!(mul_wrapped, MulWrapped), + Nand(nand) => binary!(nand, Nand), + Neg(neg) => unary!(neg, Negate), + Nor(nor) => binary!(nor, Nor), + Not(not) => unary!(not, Not), + Or(or) => binary!(or, BitwiseOr), + Pow(pow) => binary!(pow, Pow), + PowWrapped(pow_wrapped) => binary!(pow_wrapped, PowWrapped), + Rem(rem) => binary!(rem, Rem), + RemWrapped(rem_wrapped) => binary!(rem_wrapped, RemWrapped), + Shl(shl) => binary!(shl, Shl), + ShlWrapped(shl_wrapped) => binary!(shl_wrapped, ShlWrapped), + Shr(shr) => binary!(shr, Shr), + ShrWrapped(shr_wrapped) => binary!(shr_wrapped, ShrWrapped), + SignVerify(_) => todo!(), + Square(square) => unary!(square, Square), + SquareRoot(sqrt) => unary!(sqrt, SquareRoot), + Sub(sub) => binary!(sub, Sub), + SubWrapped(sub_wrapped) => binary!(sub_wrapped, SubWrapped), + Ternary(ternary) => { + let condition = self.operand_value(&ternary.operands()[0]); + let result = match condition { + Value::Bool(true) => &ternary.operands()[1], + Value::Bool(false) => &ternary.operands()[2], + _ => panic!(), + }; + self.increment_instruction_index(); + (self.operand_value(result), ternary.destinations()[0].clone()) + } + Xor(xor) => binary!(xor, Xor), + }; + + self.set_register(destination, value); + + Ok(()) + } + + fn outputs(&self) -> Vec { + let Some(Frame { element, .. }) = self.frames.last() else { + panic!("frame expected"); + }; + let Element::AleoExecution { context, .. } = element else { + panic!("aleo execution expected"); + }; + + let mut result = match context { + AleoContext::Closure(closure) => { + closure.outputs().iter().map(|output| self.operand_value(output.operand())).collect() + } + AleoContext::Function(function) => { + function.outputs().iter().map(|output| self.operand_value(output.operand())).collect() + } + AleoContext::Finalize(_finalize) => Vec::new(), + }; + + if result.is_empty() { + result.push(Value::Unit); + } + result + } + + fn step_aleo_command(&mut self, command: Command) -> Result<()> { + use Command::*; + match command { + Instruction(instruction) => self.step_aleo_instruction(instruction)?, + Await(await_) => { + let Value::Future(future) = self.get_register(await_.register().clone()) else { + halt_no_span!("attempted to await a non-future"); + }; + self.contexts.add_future(future.clone()); + self.increment_instruction_index(); + } + Contains(_) => todo!(), + Get(_) => todo!(), + GetOrUse(_) => todo!(), + RandChaCha(_) => todo!(), + Remove(_) => todo!(), + Set(_) => todo!(), + BranchEq(branch_eq) => { + let first = self.operand_value(branch_eq.first()); + let second = self.operand_value(branch_eq.second()); + if first.eq(&second) { + self.branch(branch_eq.position()); + } else { + self.increment_instruction_index(); + } + } + BranchNeq(branch_neq) => { + let first = self.operand_value(branch_neq.first()); + let second = self.operand_value(branch_neq.second()); + if first.neq(&second) { + self.branch(branch_neq.position()); + } else { + self.increment_instruction_index(); + } + } + Position(_) => {} + } + Ok(()) + } + + fn branch(&mut self, label: &Identifier) { + let Some(Frame { + element: Element::AleoExecution { instruction_index, context: AleoContext::Finalize(finalize), .. }, + .. + }) = self.frames.last_mut() + else { + panic!(); + }; + for (i, cmd) in finalize.commands().iter().enumerate() { + if let Command::Position(position) = cmd { + if position.name() == label { + *instruction_index = i; + return; + } + } + } + panic!("branch to nonexistent label {}", label); + } + + pub fn step_aleo(&mut self) -> Result<()> { + if let Some(command) = self.next_command().cloned() { + self.step_aleo_command(command)?; + } else if let Some(instruction) = self.next_instruction().cloned() { + self.step_aleo_instruction(instruction)?; + } + + if self.execution_complete() { + let mut outputs = self.outputs(); + self.frames.pop(); + if outputs.len() > 1 { + self.values.push(Value::Tuple(outputs)); + } else { + self.values.push(mem::take(&mut outputs[0])); + } + } + + Ok(()) + } +} + +fn snarkvm_literal_type_to_type(snarkvm_type: LiteralType) -> Type { + use Type::*; + match snarkvm_type { + LiteralType::Address => Address, + LiteralType::Boolean => Boolean, + LiteralType::Field => Field, + LiteralType::Group => Group, + LiteralType::I8 => Integer(IntegerType::I8), + LiteralType::I16 => Integer(IntegerType::I16), + LiteralType::I32 => Integer(IntegerType::I32), + LiteralType::I64 => Integer(IntegerType::I64), + LiteralType::I128 => Integer(IntegerType::I128), + LiteralType::U8 => Integer(IntegerType::U8), + LiteralType::U16 => Integer(IntegerType::U16), + LiteralType::U32 => Integer(IntegerType::U32), + LiteralType::U64 => Integer(IntegerType::U64), + LiteralType::U128 => Integer(IntegerType::U128), + LiteralType::Scalar => Scalar, + LiteralType::Signature => todo!(), + LiteralType::String => todo!(), + } +} + +fn snarkvm_literal_to_value(literal: Literal) -> Value { + match literal { + Literal::Address(x) => Value::Address(x), + Literal::Boolean(x) => Value::Bool(*x), + Literal::Field(x) => Value::Field(x), + Literal::Group(x) => Value::Group(x), + Literal::I8(x) => Value::I8(*x), + Literal::I16(x) => Value::I16(*x), + Literal::I32(x) => Value::I32(*x), + Literal::I64(x) => Value::I64(*x), + Literal::I128(x) => Value::I128(*x), + Literal::U8(x) => Value::U8(*x), + Literal::U16(x) => Value::U16(*x), + Literal::U32(x) => Value::U32(*x), + Literal::U64(x) => Value::U64(*x), + Literal::U128(x) => Value::U128(*x), + Literal::Scalar(x) => Value::Scalar(x), + Literal::Signature(_) | Literal::String(_) => tc_fail!(), + } +} + +fn value_to_snarkvm_literal(value: Value) -> Literal { + match value { + Value::Bool(x) => Literal::Boolean(Boolean::new(x)), + Value::U8(x) => Literal::U8(Integer::new(x)), + Value::U16(x) => Literal::U16(Integer::new(x)), + Value::U32(x) => Literal::U32(Integer::new(x)), + Value::U64(x) => Literal::U64(Integer::new(x)), + Value::U128(x) => Literal::U128(Integer::new(x)), + Value::I8(x) => Literal::I8(Integer::new(x)), + Value::I16(x) => Literal::I16(Integer::new(x)), + Value::I32(x) => Literal::I32(Integer::new(x)), + Value::I64(x) => Literal::I64(Integer::new(x)), + Value::I128(x) => Literal::I128(Integer::new(x)), + Value::Group(x) => Literal::Group(x), + Value::Field(x) => Literal::Field(x), + Value::Scalar(x) => Literal::Scalar(x), + Value::Address(x) => Literal::Address(x), + Value::Array(_) | Value::Tuple(_) | Value::Unit | Value::Future(_) | Value::Struct(_) => tc_fail!(), + } +} diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index 2cbc5a2bb8..1afe8671b8 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -18,12 +18,12 @@ use leo_ast::{AccessExpression, AssertVariant, Ast, ConsoleFunction, Expression, use leo_errors::{CompilerError, InterpreterHalt, LeoError, Result, emitter::Handler}; use leo_span::{Span, source_map::FileName, symbol::with_session_globals}; -use snarkvm::prelude::TestnetV0; +use snarkvm::prelude::{Program, TestnetV0}; use colored::*; use std::{ collections::HashMap, - fmt::Display, + fmt::{Display, Write as _}, fs, path::{Path, PathBuf}, }; @@ -34,6 +34,8 @@ use util::*; mod cursor; use cursor::*; +mod cursor_aleo; + mod value; use value::*; @@ -61,6 +63,7 @@ enum InterpreterAction { LeoInterpretOver(String), RunFuture(usize), Breakpoint(Breakpoint), + PrintRegister(u64), Into, Over, Step, @@ -68,12 +71,18 @@ enum InterpreterAction { } impl Interpreter { - fn new<'a, P: 'a + AsRef>( - source_files: impl IntoIterator, + fn new<'a, P: 'a + AsRef, Q: 'a + AsRef>( + leo_source_files: impl IntoIterator, + aleo_source_files: impl IntoIterator, signer: SvmAddress, block_height: u32, ) -> Result { - Self::new_impl(&mut source_files.into_iter().map(|p| p.as_ref()), signer, block_height) + Self::new_impl( + &mut leo_source_files.into_iter().map(|p| p.as_ref()), + &mut aleo_source_files.into_iter().map(|p| p.as_ref()), + signer, + block_height, + ) } fn get_ast(path: &Path, handler: &Handler, node_builder: &NodeBuilder) -> Result { @@ -83,7 +92,12 @@ impl Interpreter { leo_parser::parse_ast::(handler, node_builder, &text, source_file.start_pos) } - fn new_impl(source_files: &mut dyn Iterator, signer: SvmAddress, block_height: u32) -> Result { + fn new_impl( + leo_source_files: &mut dyn Iterator, + aleo_source_files: &mut dyn Iterator, + signer: SvmAddress, + block_height: u32, + ) -> Result { let handler = Handler::default(); let node_builder = Default::default(); let mut cursor: Cursor<'_> = Cursor::new( @@ -92,14 +106,14 @@ impl Interpreter { block_height, ); let mut filename_to_program = HashMap::new(); - for path in source_files { + for path in leo_source_files { let ast = Self::get_ast(path, &handler, &node_builder)?; // TODO: This leak is silly. let ast = Box::leak(Box::new(ast)); for (&program, scope) in ast.ast.program_scopes.iter() { filename_to_program.insert(path.to_path_buf(), program.to_string()); for (name, function) in scope.functions.iter() { - cursor.functions.insert(GlobalId { program, name: *name }, function); + cursor.functions.insert(GlobalId { program, name: *name }, FunctionVariant::Leo(function)); } for (name, composite) in scope.structs.iter() { @@ -126,6 +140,46 @@ impl Interpreter { } } + for path in aleo_source_files { + let aleo_program = Self::get_aleo_program(path)?; + // TODO: Another goofy leak. + let aleo_program = Box::leak(Box::new(aleo_program)); + let program = snarkvm_identifier_to_symbol(aleo_program.id().name()); + filename_to_program.insert(path.to_path_buf(), program.to_string()); + + for (name, struct_type) in aleo_program.structs().iter() { + cursor.structs.insert( + GlobalId { program, name: snarkvm_identifier_to_symbol(name) }, + struct_type.members().keys().map(snarkvm_identifier_to_symbol).collect(), + ); + } + + for (name, record_type) in aleo_program.records().iter() { + cursor.structs.insert( + GlobalId { program, name: snarkvm_identifier_to_symbol(name) }, + record_type.entries().keys().map(snarkvm_identifier_to_symbol).collect(), + ); + } + + for (name, _mapping) in aleo_program.mappings().iter() { + cursor.mappings.insert(GlobalId { program, name: snarkvm_identifier_to_symbol(name) }, HashMap::new()); + } + + for (name, function) in aleo_program.functions().iter() { + cursor.functions.insert( + GlobalId { program, name: snarkvm_identifier_to_symbol(name) }, + FunctionVariant::AleoFunction(function), + ); + } + + for (name, closure) in aleo_program.closures().iter() { + cursor.functions.insert( + GlobalId { program, name: snarkvm_identifier_to_symbol(name) }, + FunctionVariant::AleoClosure(closure), + ); + } + } + Ok(Interpreter { cursor, handler, @@ -136,6 +190,12 @@ impl Interpreter { }) } + fn get_aleo_program(path: &Path) -> Result> { + let text = fs::read_to_string(path).map_err(|e| CompilerError::file_read_error(path, e))?; + let program = text.parse()?; + Ok(program) + } + fn action(&mut self, act: InterpreterAction) -> Result> { use InterpreterAction::*; @@ -196,6 +256,19 @@ impl Interpreter { StepResult { finished: false, value: None } } + PrintRegister(register_index) => { + let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.cursor.frames.last() + else { + halt_no_span!("cannot print register - not currently interpreting Aleo VM code"); + }; + + if let Some(value) = registers.get(register_index) { + StepResult { finished: false, value: Some(value.clone()) } + } else { + halt_no_span!("no such register {register_index}"); + } + } + Run => { while !self.cursor.frames.is_empty() { if let Some((program, line)) = self.current_program_and_line() { @@ -226,25 +299,76 @@ impl Interpreter { Element::Expression(expression) => format!("{expression}"), Element::Block { block, .. } => format!("{block}"), Element::DelayedCall(gid) => format!("Delayed call to {gid}"), + Element::AleoExecution { context, instruction_index, .. } => match context { + AleoContext::Closure(closure) => closure.instructions().get(instruction_index).map(|i| format!("{i}")), + AleoContext::Function(function) => { + function.instructions().get(instruction_index).map(|i| format!("{i}")) + } + AleoContext::Finalize(finalize) => finalize.commands().get(instruction_index).map(|i| format!("{i}")), + } + .unwrap_or_else(|| "...".to_string()), }) } fn view_current_in_context(&self) -> Option { - let span = self.current_span()?; - if span == Default::default() { - return None; + if let Some(Frame { element: Element::AleoExecution { context, instruction_index, .. }, .. }) = + self.cursor.frames.last() + { + // For Aleo VM code, there are no spans; just print out the code without referring to the source code. + + fn write_all(items: impl Iterator, instruction_index: usize) -> String { + let mut result = String::new(); + for (i, item) in items.enumerate() { + if i == instruction_index { + let temp = format!(" {item}").red(); + writeln!(&mut result, "{temp}").expect("write"); + } else { + writeln!(&mut result, " {item}").expect("write"); + } + } + result + } + + let (heading, inputs, instructions, outputs) = match context { + AleoContext::Closure(closure) => ( + format!("closure {}\n", closure.name()), + write_all(closure.inputs().iter(), usize::MAX), + write_all(closure.instructions().iter(), *instruction_index), + write_all(closure.outputs().iter(), usize::MAX), + ), + AleoContext::Function(function) => ( + format!("function {}\n", function.name()), + write_all(function.inputs().iter(), usize::MAX), + write_all(function.instructions().iter(), *instruction_index), + write_all(function.outputs().iter(), usize::MAX), + ), + AleoContext::Finalize(finalize) => ( + format!("finalize {}\n", finalize.name()), + write_all(finalize.inputs().iter(), usize::MAX), + write_all(finalize.commands().iter(), *instruction_index), + "".to_string(), + ), + }; + + Some(format!("{heading}{inputs}{instructions}{outputs}")) + } else { + // For Leo code, we use spans to print the original source code. + let span = self.current_span()?; + if span == Default::default() { + return None; + } + with_session_globals(|s| { + let source_file = s.source_map.find_source_file(span.lo)?; + let first_span = Span::new(source_file.start_pos, span.lo); + let last_span = Span::new(span.hi, source_file.end_pos); + Some(format!( + "{}{}{}", + s.source_map.contents_of_span(first_span)?, + s.source_map.contents_of_span(span)?.red(), + s.source_map.contents_of_span(last_span)?, + )) + }) } - with_session_globals(|s| { - let source_file = s.source_map.find_source_file(span.lo)?; - let first_span = Span::new(source_file.start_pos, span.lo); - let last_span = Span::new(span.hi, source_file.end_pos); - Some(format!( - "{}{}{}", - s.source_map.contents_of_span(first_span)?, - s.source_map.contents_of_span(span)?.red(), - s.source_map.contents_of_span(last_span)?, - )) - }) } fn current_program_and_line(&self) -> Option<(String, usize)> { @@ -396,8 +520,13 @@ fn kill_span_expression(expression: &mut Expression) { /// Load all the Leo source files indicated and open the interpreter /// to commands from the user. -pub fn interpret(filenames: &[PathBuf], signer: SvmAddress, block_height: u32) -> Result<()> { - let mut interpreter = Interpreter::new(filenames.iter(), signer, block_height)?; +pub fn interpret( + leo_filenames: &[PathBuf], + aleo_filenames: &[PathBuf], + signer: SvmAddress, + block_height: u32, +) -> Result<()> { + let mut interpreter = Interpreter::new(leo_filenames.iter(), aleo_filenames.iter(), signer, block_height)?; let mut buffer = String::new(); println!("{}", INSTRUCTIONS); loop { @@ -437,6 +566,15 @@ pub fn interpret(filenames: &[PathBuf], signer: SvmAddress, block_height: u32) - InterpreterAction::Breakpoint(breakpoint) } else if let Some(rest) = s.strip_prefix("#into ").or(s.strip_prefix("#i ")) { InterpreterAction::LeoInterpretInto(rest.trim().into()) + } else if let Some(rest) = s.strip_prefix("#print ").or(s.strip_prefix("#p ")) { + let trimmed = rest.trim(); + let without_r = trimmed.strip_prefix("r").unwrap_or(trimmed); + if let Ok(num) = without_r.parse::() { + InterpreterAction::PrintRegister(num) + } else { + println!("failed to parse register number {trimmed}"); + continue; + } } else { InterpreterAction::LeoInterpretOver(s.trim().into()) } diff --git a/interpreter/src/util.rs b/interpreter/src/util.rs index bfe1e34fd0..e68bc5cdaa 100644 --- a/interpreter/src/util.rs +++ b/interpreter/src/util.rs @@ -15,7 +15,9 @@ // along with the Leo library. If not, see . use leo_errors::{InterpreterHalt, Result}; -use leo_span::Span; +use leo_span::{Span, Symbol}; + +use snarkvm::prelude::{Identifier, TestnetV0}; #[macro_export] macro_rules! tc_fail { @@ -24,6 +26,13 @@ macro_rules! tc_fail { }; } +#[macro_export] +macro_rules! halt_no_span { + ($($x:tt)*) => { + return Err(InterpreterHalt::new(format!($($x)*)).into()) + } +} + #[macro_export] macro_rules! halt { ($span: expr) => { @@ -59,3 +68,8 @@ impl ExpectTc for Result { self.map_err(|_e| InterpreterHalt::new_spanned("type failure".into(), span).into()) } } + +pub fn snarkvm_identifier_to_symbol(id: &Identifier) -> Symbol { + let s = id.to_string(); + Symbol::intern(&s) +} diff --git a/leo/cli/commands/debug.rs b/leo/cli/commands/debug.rs index 32c8194a3e..6a51469f91 100644 --- a/leo/cli/commands/debug.rs +++ b/leo/cli/commands/debug.rs @@ -30,6 +30,9 @@ use super::*; /// Debugs an Aleo program through the interpreter. #[derive(Parser, Debug)] pub struct LeoDebug { + #[arg(long, help = "Use these source files instead of finding source files through the project structure.", num_args = 1..)] + pub(crate) paths: Vec, + #[arg(long, help = "The block height, accessible via block.height.", default_value = "0")] pub(crate) block_height: u32, @@ -83,28 +86,45 @@ fn handle_debug(command: &LeoDebug, context: Context) -> Result<()> let private_key = context.get_private_key(&None)?; let address = Address::try_from(&private_key)?; - // Retrieve all local dependencies in post order - let main_sym = Symbol::intern(&program_id.name().to_string()); - let mut retriever = Retriever::::new( - main_sym, - &package_path, - &home_path, - context.get_endpoint(&command.compiler_options.endpoint)?.to_string(), - ) - .map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; - let mut local_dependencies = - retriever.retrieve().map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; - - // Push the main program at the end of the list. - local_dependencies.push(main_sym); - - let paths: Vec = local_dependencies - .into_iter() - .map(|dependency| { - let base_path = retriever.get_context(&dependency).full_path(); - base_path.join("src/main.leo") - }) - .collect(); - - leo_interpreter::interpret(&paths, address, command.block_height) + if command.paths.is_empty() { + // Retrieve all local dependencies in post order + let main_sym = Symbol::intern(&program_id.name().to_string()); + let mut retriever = Retriever::::new( + main_sym, + &package_path, + &home_path, + context.get_endpoint(&command.compiler_options.endpoint)?.to_string(), + ) + .map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; + let mut local_dependencies = + retriever.retrieve().map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; + + // Push the main program at the end of the list. + local_dependencies.push(main_sym); + + let paths: Vec = local_dependencies + .into_iter() + .map(|dependency| { + let base_path = retriever.get_context(&dependency).full_path(); + base_path.join("src/main.leo") + }) + .collect(); + + leo_interpreter::interpret(&paths, &[], address, command.block_height) + } else { + let leo_paths: Vec = command + .paths + .iter() + .filter(|path_str| path_str.ends_with(".leo")) + .map(|path_str| path_str.into()) + .collect(); + let aleo_paths: Vec = command + .paths + .iter() + .filter(|path_str| !path_str.ends_with(".leo")) + .map(|path_str| path_str.into()) + .collect(); + + leo_interpreter::interpret(&leo_paths, &aleo_paths, address, command.block_height) + } }